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,一经查实,立即删除!

相关文章

c#阿里云服务器发送邮件

public static void SendMailUse(){string host "smtp.lotusest.com";// 邮件服务器smtp.163.com表示网易邮箱服务器 string userName "s********t.com";// 发送端账号 string password "11111111";// 发送端密码(这个客户端重置后的密码…

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…

集成JavaFX和Swing(修订版)

我刚刚完成了对使用Swing的应用程序组件的重写&#xff0c;现在正在使用JavaFX&#xff0c;最后得到了与更大的swing应用程序集成的JavaFX组件。 这是一个很大的应用程序&#xff0c;重写花了我一段时间&#xff0c;最后一切都很好&#xff0c;我很高兴自己做到了。 您可能想在…

C++内存模型

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

java bag_Java - T---bag - 博客园

Java是一门面向对象编程语言&#xff0c;不仅吸收了C语言的各种优点&#xff0c;还摒弃了C里难以理解的多继承、指针等概念&#xff0c;因此Java语言具有功能强大和简单易用两个特征。Java语言作为静态面向对象编程语言的代表&#xff0c;极好地实现了面向对象理论&#xff0c;…

IT服务(运维)管理实施的几个要点--序言

IT服务&#xff08;运维&#xff09;管理&#xff08;不是IT运维技术&#xff09;是IT行业当中相对比较“窄”的一个分支&#xff0c;通常只被金融、电信等大型数据中心的中高层管理人员所关注。但是根据笔者多年从事IT服务和服务管理的经验来看&#xff0c;IT服务并不是一件容…

HTML条件注释

前面的话 IE条件注释是微软从IE5开始就提供的一种非标准逻辑语句&#xff0c;作用是可以灵活的为不同IE版本浏览器导入不同html元素。很显然这种方法的最大好处就在于属于微软官方给出的兼容解决办法而且还能通过W3C的效验 识别IE 因为从IE10开始&#xff0c;IE浏览器已经不再支…

MongoDB主键是您的朋友

MongoDB集合中的所有文档都有一个主键&#xff0c;称为_id 。 该字段在插入后自动分配给文档&#xff0c;因此几乎不需要提供它。 _id字段的有趣之处在于它是基于时间的 。 也就是说&#xff0c;基础类型的_id &#xff0c;这是ObjectId &#xff0c;是一个12字节的BSON型 &…

java getqueue 0_Java Queue的使用

Queue 实现一个先进先出的队列获取队列长度&#xff1a;size()添加元素到队尾&#xff1a;boolean add(E e) /boolean offer(E e)获取队列头部元素并删除&#xff1a;E remove() / E poll()获取队列头部元素但不删除&#xff1a;E element() / E peek()当添加或获取元素失败时t…

1015. Reversible Primes (20)

生词以及在文中意思prime 素数1.java十进制转为N进制&#xff1a;Integer.toString(int i,int radix)//返回的是i的二进制表示&#xff0c;返回类型为String&#xff0c;但是负数不适用。 N进制转为十进制&#xff1a;Integer.parseInt(String s,int radix)//radix进制的s&…

PAT 乙级 1029 旧键盘

1029 旧键盘 分数 20 作者 CHEN, Yue 单位 浙江大学 旧键盘上坏了几个键&#xff0c;于是在敲一段文字的时候&#xff0c;对应的字符就不会出现。现在给出应该输入的一段文字、以及实际被输入的文字&#xff0c;请你列出肯定坏掉的那些键。 输入格式&#xff1a; 输入在 2 行中…

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…

Spring Data Solr教程:分页

在我的Spring Data Solr教程的较早部分中&#xff0c;我们实现了一个简单的搜索功能&#xff0c;该功能用于搜索待办事项的信息。 我们搜索功能的当前实现将所有搜索结果显示在一个页面中。 对于大多数现实生活中的应用程序而言&#xff0c;这不是可行的解决方案&#xff0c;因…

消息队列01

公司项目里面用到了这个rabbitmq&#xff0c;自己以前不熟悉&#xff0c;看了代码里面的应用&#xff0c;自己也准备试着搭建下。 可以参照其他博主的这篇优秀博文&#xff1a; https://www.cnblogs.com/chengpeng15/p/5814197.html 一 前期需要了解的概念 1.什么是异步&#x…

java instanceof翻译_Java 中的instanceof简单讲解

Java 中的instanceof 运算符是用来在运行时指出对象是否是特定类的一个实例。instanceof通过返回一个布尔值来指出&#xff0c;这个对象是否是这个特定类或者是它的子类的一个实例。用法&#xff1a;result object instanceof class参数&#xff1a;Result&#xff1a;布尔类型…

Spring4有条件

Spring 4引入了一个称为Conditional的新功能&#xff0c;该功能针对于生成bean的Spring组件&#xff0c;并注视这些bean的生成&#xff0c;实质上&#xff0c;它提供了一种条件生成bean的方法。 考虑一个简单的例子&#xff1a; 我有一个名为“ CustomerService”的服务&…

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位哈、…