5个编码技巧以减少GC开销

在本文中,我们将介绍五种方法,这些方法可以使用有效的编码来帮助垃圾回收器减少分配和释放内存的CPU时间,并减少GC开销。 较长的GC通常会导致我们的代码在回收内存时被停止(也称为“停止世界”)。 duke_GCPost

一些背景

GC的建立是为了处理大量短期对象的分配(例如渲染网页等,其中大部分分配的对象在服务页面后就已过时)。

GC使用所谓的“年轻”来完成此工作–分配新对象的堆段。 每个对象都有一个“年龄”(放置在对象的标题位中),该年龄定义了它在没有回收的情况下“生存”了多少个集合。 一旦达到一定年龄,该对象将被复制到堆中称为“幸存者”或“旧”世代的另一部分。

该过程虽然有效,但仍然要付出代价。 能够减少临时分配的数量确实可以帮助我们提高吞吐量,尤其是在大规模应用程序中。

以下是五种我们可以编写日常代码的方法,这些代码可以提高内存效率,而不必花费大量时间或降低代码的可读性。

1.避免隐式字符串

字符串几乎是我们管理的每个数据结构不可或缺的一部分。 它们比其他原始值重得多,它们对内存使用量的影响更大。

要注意的最重要的事情之一是字符串是不可变的 。 分配后不能修改它们。 用于连接的运算符(例如“ +”)实际上分配了一个新的String,其中包含要连接的字符串的内容。 更糟糕的是,有一个隐式的StringBuilder对象被分配来实际完成组合它们的工作。

例如 -

a = a + b; // a and b are Strings

编译器在后台生成可比较的代码:

StringBuilder temp = new StringBuilder(a).
temp.append(b);
a = temp.toString(); // a new String is allocated here.// The previous “a” is now garbage.

但情况变得更糟。

让我们看这个例子–

String result = foo() + arg;
result += boo();
System.out.println(“result = “ + result);

在此示例中,我们在后台分配了3个StringBuilder-每个加号操作一个,另外两个Strings-一个用于保存第二个赋值的结果,另一个用于保存传递给print方法的字符串。 那是另外5个对象 ,否则看起来很简单。

考虑一下在现实世界中的代码场景中会发生什么,例如生成网页,使用XML或从文件中读取文本。 嵌套在循环结构中,您可能正在查看成百上千个隐式分配的对象。 尽管VM具有处理此问题的机制, 但它是有代价的 –由用户支付。

解决方案:减少这种情况的一种方法是主动使用StringBuilder分配。 下面的示例获得与上面的代码相同的结果,同时仅分配一个StringBuilder和一个String来保存最终结果,而不是原来的五个对象。

StringBuilder value = new StringBuilder(“result = “);
value.append(foo()).append(arg).append(boo());
System.out.println(value);

通过注意隐式分配Strings和StringBuilders的方式,可以从实质上减少大规模代码位置中的短期分配量。

2.计划清单的能力

诸如ArrayLists之类的动态集合是保存动态长度数据的最基本的结构之一。 ArrayList和其他集合(例如HashMaps和TreeMaps)是使用基础Object []数组实现的。 像字符串(char []数组本身包装)一样,数组也是不可变的。 显而易见的问题变成了-如果基础数组的大小是不变的,我们如何在集合中添加/放置项目? 答案也很明显–通过分配更多的数组

让我们看这个例子–

List<Item> items = new ArrayList<Item>();for (int i = 0; i < len; i++)
{Item item = readNextItem();items.add(item);
}

len的值确定循环结束后项目的最终长度。 但是,此值对于ArrayList的构造函数是未知的,该构造函数分配具有默认大小的新Object数组。 每当超出内部阵列的容量时,就会用足够长的新阵列替换内部阵列的容量,从而使以前的阵列成为垃圾。

如果要执行数千次循环,则可能会强制分配一个新数组,并多次收集前一个数组。 对于在大规模环境中运行的代码,这些分配和取消分配都从计算机的CPU周期中扣除。

解决方案:尽可能分配具有初始容量的列表和地图,如下所示:

List<MyObject> items = new ArrayList<MyObject>(len);

这样可以确保在运行时不会发生内部数组的不必要分配和取消分配,因为列表现在具有足够的容量开始。 如果您不知道确切的大小,最好对平均大小进行估算(例如1024、4096),并添加一些缓冲区以防止意外溢出。

3.使用有效的原始集合

Java编译器的当前版本通过使用“装箱”来支持具有原始键或值类型的数组或映射-将原始值包装在可由GC分配和回收的标准对象中。

这可能会带来一些负面影响 。 Java使用内部数组实现大多数集合。 对于添加到HashMap的每个键/值条目,分配一个内部对象来容纳两个值。 这在处理地图时是必不可少的,这意味着您每次将商品放入地图时都会进行额外的分配和可能的重新分配。 还可能会增加容量并不得不重新分配新的内部阵列。 当处理包含数千个或更多条目的大型地图时,这些内部分配可能会增加GC的成本。

一种非常常见的情况是在原始值(例如Id)和对象之间保留映射。 由于Java的HashMap是为保存对象类型(相对于基元)而构建的,因此这意味着映射中的每个插入都可以潜在地分配另一个对象来保存基元值(“装箱”它)。

标准的Integer.valueOf方法缓存0到255之间的值,但是对于每个大于0的数字,除了内部键/值输入对象之外,还将分配一个新对象。 这可能会使映射的GC开销增加三倍以上。 对于那些来自C ++背景的人来说,这确实是令人不安的消息,因为STL模板可以非常有效地解决此问题。

幸运的是,此问题正在Java的下一版本中进行。 在此之前,一些出色的库已经对其进行了相当有效的处理,这些库为Java的每种原始类型提供了原始树,映射和列表。 我强烈推荐Trove ,我已经使用了很长时间 ,发现它确实可以减少大规模代码中的GC开销。

4.使用流而不是内存缓冲区

我们在服务器应用程序中处理的大多数数据都是通过文件或数据从另一个Web服务或数据库通过网络流式传输给我们的。 在大多数情况下,传入的数据是序列化的,在我们开始对其进行操作之前,需要将其反序列化为Java对象。 这个阶段很容易出现大量的隐式分配

通常最简单的方法是使用ByteArrayInputStream,ByteBuffer将数据读取到内存中,然后将其传递给反序列化代码。

这可能是一个错误的举动 ,因为您需要在构造出新的对象时为整个数据分配和释放空间。 而且,由于数据的大小可能是未知的,您猜到了–您必须分配和取消分配内部byte []数组,以便在数据超出初始缓冲区的容量时容纳它们。

解决方案非常简单。 大多数持久性库(例如Java的本机序列化,Google的协议缓冲区等)都可以直接从传入的文件或网络流中反序列化数据,而不必将其保留在内存中,也不必分配新的内部字节数组来保存数据。随着数据的增长。 如果可以的话,请采用这种方法,而不是将数据加载到内存。 您的GC将感谢您。

5.汇总列表

不变性是一件美丽的事情,但是在某些大规模情况下,它可能会存在一些严重的缺点。 一种情况是在方法之间传递List对象。

从函数返回集合时,通常建议在方法内创建集合对象(例如ArrayList),将其填充并以不可变的Collection接口的形式返回。

在某些情况下这不能很好地工作 。 最引人注目的是将集合从多个方法调用中聚合到最终集合中。 虽然不变性提供了更高的清晰度,但在大规模情况下,这也可能意味着临时集合的大量分配。

在这种情况下,解决方案不是返回新的集合,而是将值聚合到单个集合中,该集合作为参数传递到这些方法中。

示例1(效率低下)–

List<Item> items = new ArrayList<Item>();for (FileData fileData : fileDatas)
{// Each invocation creates a new interim list with possible// internal interim arraysitems.addAll(readFileItem(fileData));
}

示例2 –

List<Item> items =new ArrayList<Item>(fileDatas.size() * avgFileDataSize * 1.5);for (FileData fileData : fileDatas)
{readFileItem(fileData, items); // fill items inside
}

示例2在遵守不变性规则(通常应遵守该规则)的同时,可以保存N个列表分配(以及任何临时数组分配)。 在大规模情况下,这可以为您的GC带来福音。

补充阅读

  • 字符串实习– http://plumbr.eu/blog/reducing-memory-usage-with-string-intern
  • 高效的包装器– http://vanillajava.blogspot.co.il/2013/04/low-gc-coding-efficient-listeners.html
  • 使用Trove – http://java-performance.info/primitive-types-collections-trove-library/

此帖子也可以在Speaker Deck上找到

参考:来自Takipi博客的JCG合作伙伴 Iris Shoor的 5种编码技巧以减少GC开销 。

翻译自: https://www.javacodegeeks.com/2013/07/5-coding-hacks-to-reduce-gc-overhead.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/368322.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

java usb 无驱打印_Windows Usb 无驱动打印

\?\USB#VID_8866&PID_0100#0001B0000000#{a5dcbf10-6530-11d2-901f-00c04fb951ed}USB小票打印解决办法一、需要驱动&#xff0c;无需更改程序安装USB打印驱动&#xff0c;然后共享打印机&#xff0c;通过 “\\计算机\打印机名”的形式&#xff0c;按端口方式写。1二、直接…

需要学习的东西列表

1.Python2.webservice3.requirejs4.idea5.webService6.redis7.doubble8.mongDB9.zookper 大数据学习曲线&#xff1a;课程一、大数据运维之Linux基础课程二、大数据开发核心技术-Hadoop 2.x从入门到精通课程三、大数据开发核心技术-大数据仓库Hive精讲课程四、大数据协作框架-S…

微信小程序 引用其他js里的方法

微信小程序中&#xff0c;在微信官方开发文档我们可以知道 小程序的目录结构 。 一个小程序页面由四个文件组成&#xff0c;一个小程序页面的四个文件具有相同路径与文件名&#xff0c;由此我们可知一个小程序页面对应着一个跟页面同名的js文件。可是当有些公共方法&#xff0…

C++内存模型

C内存模型 一文了解所有C内存的问题 AlexCool 目录 一 C内存模型 二 C对象内存模型 三 C程序运行内存空间模型 四 C栈内存空间模型 五 C堆内存空间模型 六 C内存问题及常用的解决方法 七 C程序内存性能测试 环境&#xff1a; uname -a Linux alexfeng 3.19.0-15-generic #…

css之absolute

一、absolute和float有相同的特性&#xff0c;包裹性和破坏性 1、absolute和float的相似(看下面的demo&#xff0c;如果图片在左上角&#xff0c;那么用float和absolute都一样) 1 <!doctype html>2 <html>3 <head>4 <meta charset"utf-8">5…

inline「一」:从 image 底部白边初识 line-height

本文首发于个人博客 http://www.lijundong.com/image-and-line-height/ 今天在做一个静态页面时&#xff0c;图片底部出现一条 3px 高度的白边&#xff0c;既不是 margin 也不是 padding&#xff0c;找了好久没能解决&#xff0c;后来才发现与 line-height 相关&#xff0c;问…

(转) STM32--ADC

原标题&#xff1a;STM32之ADC步骤小技巧&#xff08;英文&#xff09; 看到标题&#xff0c;别吓到哈、并不是要用英文写、至于原因是什么、请往下看&#xff1a; 言归正传&#xff1a;STM32的ADC模块的特色 1、1MHz转换速率、12位转换结果&#xff08;12位、记住这个12位哈、…

嗨,那里有回调!

因为是我的书包&#xff0c;所以我喜欢JavaScript 。 实际上&#xff0c;我已经开始喜欢JavaScritp的面向异步回调的编程风格 。 因此&#xff0c;当我发现自己处于非JavaScript环境中时&#xff08;例如Java&#xff09; &#xff0c;我往往会错过使用回调的机会。 好消息是…

GC内存可视化器教程–第一部分

正如您从以前的文章中可能已经读到的那样&#xff0c;要获得的Java程序员的一项关键技能就是理解和评估JVM的运行状况的能力&#xff0c;例如Java堆内存占用量以及垃圾回收过程。 为了实现上述目标&#xff0c;所有JVM供应商&#xff08;Oracle&#xff0c;IBM等&#xff09;都…

设置表格边框颜色

1、源码如下&#xff1a; <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html><head><title>设置表格边框颜色</title><meta http-equiv"keywords" content"keyword1,keyword2,keyword3"…

java se程序设计_JavaSE--Java 的基本程序设计结构

Java 对大小写敏感Java 中定义类名的规则很宽松。名字必须以字母开头&#xff0c;后面可以跟字母和数字的任意组合。长度基本上没有限制。但是不能使用 Java 保留字作为类名。标准的命名规范为&#xff1a;类名是以大写字母开头的名词。如果名字由多个单词组成&#xff0c;每个…

Python开发【第十九篇】:Python操作MySQL

本篇对于Python操作MySQL主要使用两种方式&#xff1a; 原生模块 pymsqlORM框架 SQLAchemypymsql pymsql是Python中操作MySQL的模块&#xff0c;其使用方法和MySQLdb几乎相同。 下载安装 1pip3 install pymysql使用操作 1、执行SQL 123456789101112131415161718192021222324252…

20180705 考试记录

T1 货物运输弱化版 题解&#xff1a; 倒着跑最短路就行没仔细看题凉凉 code: #include<cstdio> #include<iostream> #include<cstring> #include<algorithm> #define F(i,a,b) for(register int i(a);i<(b);i) using namespace std;int rd() {int x…

mysql集群跨地域同步部署_跨地域冗余 - 跨数据中心部署方案 - 《TiDB v2.1 用户文档》 - 书栈网 · BookStack...

跨数据中心部署方案作为 NewSQL 数据库&#xff0c;TiDB 兼顾了传统关系型数据库的优秀特性以及 NoSQL 数据库可扩展性&#xff0c;以及跨数据中心(下文简称“中心”)场景下的高可用。本文档旨在介绍跨数据中心部署的不同解决方案。三中心部署方案TiDB, TiKV, PD 分别分布在 3 …

使用Maven进行硒测试自动化

今天&#xff0c;我想帮助您更好地管理自动GUI测试&#xff08;Selenium&#xff09;。 在过去&#xff0c;我已经看到人们处理此问题的许多不同方式。 有些人只是使用Selenium-IDE编写这些普通HTML TestCases&#xff0c;将其存储在HDD上的某个位置&#xff0c;并在需要时手动…

js小练习题

1.2018年01月5日 11:40:30 星期三 1 <!DOCTYPE html>2 <html lang"en">3 <head>4 <meta charset"UTF-8">5 <title>Title</title>6 <script>7 8 function getCurrentDate(){9 //1. …

OC之OBJC2_UNAVAILABLE

OC之OBJC2_UNAVAILABLE】 1、What is OBJC2_UNAVAILABLE macro mean&#xff1f; 意即在OBJC2.0中&#xff0c;这些东西将被删除。 转自 https://www.cnblogs.com/tekkaman/archive/2013/04/24/3040727.html转载于:https://www.cnblogs.com/-WML-/p/9269067.html

使用prismjs为网站添加代码高亮功能

prismjs 是一款轻量、可扩展的代码语法高亮库&#xff0c;使用现代化的 Web 标准构建&#xff0c;使用 Prismjs 可以快速为网站添加代码高亮功能&#xff0c;支持超过113中编程语言&#xff0c;还支持多种插件&#xff0c;是简洁、高效的代码高亮解决方案。科技爱好者博客就是使…

Mockito – JAXB的RETURNS_DEEP_STUBS

很抱歉没有写一段时间&#xff0c;但是我正忙于为DZone编写JBoss Drools Refcard&#xff0c;而且我正在写一本有关Mockito的书&#xff0c;因此我没有太多时间来写博客了…… 无论如何&#xff0c;最近在我当前的项目中&#xff0c;我对使用Mockito和JAXB结构进行单元测试有一…

协作机器人(Collaborative-Robot)安全碰撞的速度与接触力

协作机器人&#xff08;Collaborative-Robot&#xff09;的安全碰撞速度和接触力是一个非常重要的安全指标。在设计和使用协作机器人时&#xff0c;必须确保其与人类或其他物体的碰撞不会对人员造成伤害。 对于协作机器人的安全碰撞速度&#xff0c;一般会设定一个上限值&…