`
xinklabi
  • 浏览: 1586684 次
  • 性别: Icon_minigender_1
  • 来自: 吉林
文章分类
社区版块
存档分类
最新评论

优化技巧分享:把内存消耗降低至原来的1/20

 
阅读更多

摘要:Plumbr是一家Java存泄露检测器开发公司,在最近的客户报告中,他们发现了一个内存耗尽相关的问题。在检测后他们查出了问题所在,通过优化最终降低了21.5倍的堆内存。

这是最近发生的又一起内存相关的事件了。这个案例是从一个最近的客户报告中提取出来,一个异常运行的应用在其产品中反复报告内存耗尽。

这个症状是由我们的一个实验性功能发现,它主要用来监测某一类数据结构的使用情况。它提供了一个信号探针,结果会指向问题源代码的某一位置。为了保护客户的隐私,我们人为重建了该例子并保持它同原真实场景在技术层面的一致性。你可以免费在此处 下载到源码

故事开始于一组从外界源加载进来的对象。同外部的信息交互是基于XML的接口,这本身并没什么大不了的,但事实上“基于XML的格式进行通讯”的实现细节被分散到了系统的每一个角落。 传入系统的文档是首先被转换成XMLBean实例,然后在整个系统范围内被使用,这中做法听起来有点傻。

整个问题中最核心的部分是一个延迟加载的缓冲方案。缓存的对象是“Person”的实例:

 

1
2
3
4
5
6
7
// Imports and methods removed to improve readability
public class Person {
    private String id;
    private Date dateOfBirth;
    private String forename;
    private String surname;
}

 

 

你也许会说这才能消耗多少内存呢。但当我们揭开进一步的细节时,发现事情就变了味了。表面上根据设计,声称实现只用到的诸如上文提到的那样一些简单的类,但真实的情形是使用了基于模型生成的数据结构。使用的模型是诸如下面的这个简化的XSD片段。

 

1
2
3
4
5
6
<xs:schema targetNamespace="http://plumbr.eu" xmlns:xs="http://www.w3.org/2001/XMLSchema"
        elementFormDefault="qualified"> <xs:element name="person"> <xs:complexType>
        <xs:sequence> <xs:element name="id" type="xs:string"/> <xs:element
        name="dateOfBirth" type="xs:dateTime"/> <xs:element name="forename"
        type="xs:string"/> <xs:element name="surname" type="xs:string"/>
        </xs:sequence> </xs:complexType> </xs:element> </xs:schema>

 

 

使用 XMLBeans,开发者生成了该模型,并在真实的场景中使用。现在我们回到开始的这个缓存的方案上来,假设它设计初衷是为了支持最多1.3M Person类的实例,而我们实际却要塞进去同等数量的大家伙,这从根上就注定了失败。

跑一组测试用例后,发现1.3M个基于XMLBean的生成的实例需要消耗大概1.5GB的堆空间。我们当时想这肯定可以做的更好。

第一个改进是显而易见的,外部同系统内部集成的实现细节是不应该把影响传递给系统的每一个角落的。所以我们把缓存改成了使用简单的  java.util.HashMap<Long, Person>。ID是键,Person是值。我们发现内存的消耗立即降低到了214MB。但这还不能令我们满意。

由于Map中的键是一个数,我们有十足的理由使用 Trove Collections来进一步降低它的内存消耗。这在实现上的改动很快,我们只需把  HashMap 改成  TLongObjectHashMap<Person> ,堆的消耗进一步降低到了143MB。

活干到这个程度我们已经可以收工了,但是工程师的好奇心驱使我们要更进一步。不由自主的我们发现了系统的数据存在着大量的重复信息。例如Date Of Birth其实已经在ID中编码了,所以Date Of Birth可以直接从ID中得到,而不必使用额外的空间去它。

经过改良,Person类现在变成了这个样子:

 

1
2
3
4
5
6
// Imports and methods removed to improve readability
public class Person {
    private String id;
    private String forename;
    private String surname;
}

 

 

重新跑一边测试证实我们的改进的确有效,堆消耗降低到了93MB。但是我们还未满足。

该应用在64位的机器上使用老的JDK6。默认情况下,这么做不能 压缩普通对象的指针的。通过参数” -XX:UseCompressedOops“切换到压缩模式使我们获得了额外的收获,现在我们的内存消耗降低到了73MB。

当然,我们还能走的更远。比如基于键值建立B-tree,但这已经开始影响到了代码的可读性,所以我们决定到此为止。降低21.5倍的堆内存应该已经是一个足够好的结果了。

让我们再重复一下学到了什么

如果你对这个实验很好奇,请在此处 下载相关的代码。使用到的的测量工具和其具体描述可以在这篇 博文找到。

 

  • 别把同外部模块的整合影响到系统的每一个角落
  • 冗余的数据可能带来开销。在可能的情况下尽量消除它
  • 基本数据类型是你最经常打交道的朋友,务必知道些关于它们的工具,如果还没玩过 Trove请立刻开始吧
  • JVM自带的优化技术不可忽视

原文链接:  Nikita Salnikov-Tarnovski ,编译:感谢@ NULL_文龙 的热心翻译

译文链接: http://blog.jobbole.com/40666/

分享到:
评论

相关推荐

    代码优化.有效使用内存

    #### 4.3 缓存优化技巧 - **缓存行对齐**:确保数据在内存中对齐,使得每次访问都能充分利用缓存行,减少未命中率。 - **循环优化**:调整循环顺序或使用特定的数据布局方式,使得数据访问模式更符合缓存的行为特点...

    Android 帧动画优化实现可减少内存使用

    然而,如果不进行优化,帧动画可能会导致内存消耗过大,影响应用性能,甚至引发ANR(Application Not Responding)错误。本篇文章将深入探讨如何优化Android帧动画以降低内存使用。 首先,理解帧动画的工作原理至关...

    优化内存优化内存优化内存

    以上方法涵盖了从硬件设置到软件优化的各个方面,通过实施这些技巧,可以显著提升计算机的内存使用效率和整体性能。然而,每台计算机的配置和使用情况不同,因此,在进行任何系统更改前,建议先备份重要数据,并根据...

    Chrome标签和窗口技巧 降内存消耗.docx

    通过掌握一些特定的标签和窗口管理技巧,用户不仅可以提升浏览体验,还能有效降低内存消耗。以下是一些实用的方法: 1. **重新打开最后浏览的页面** 默认情况下,Chrome会在启动时打开主页。如果你希望它恢复到...

    JavaScript性能优化技巧分享共8页.pdf.zip

    这份"JavaScript性能优化技巧分享共8页.pdf.zip"压缩包文件很可能是对一些关键优化策略的总结,虽然我们无法直接查看具体内容,但根据标题和标签,我们可以探讨一些常见的JavaScript性能优化方法。 1. **延迟加载...

    flash制作和as编码优化技巧

    在Flash制作和AS编码优化技巧方面,有很多细节和策略可以提升你的作品性能,使其运行更加流畅,用户体验更佳。这份名为“flashplatform_optimizing_content.pdf”的文档很可能包含了丰富的优化方法,涵盖从基本的...

    《Oracle查询优化改写技巧与案例》PDF版本下载.txt

    根据提供的文件信息,本文将对《Oracle查询优化改写技巧与案例》这一主题进行详细的解析,涵盖Oracle查询优化的基本概念、重要性、改写技巧及其实际应用案例。 ### 一、Oracle查询优化概述 #### 1.1 查询优化定义 ...

    Flash,Flex和AIR应用开发内存监测及优化技巧

    布局:布局的合理安排可以减少不必要的组件重绘,从而降低内存消耗。开发者应该优化布局,减少组件数量和层级深度。 AIR相关问题:Adobe AIR应用程序在运行时可能会遇到一些特有的内存问题,比如本地共享对象(LSO...

    《andrioid内存优化》PDF

    《Android内存优化》PDF提供了一套系统性的方法来帮助开发者理解Android内存管理机制,并掌握有效的优化技巧。以下是对这份资料中可能涵盖的关键知识点的详细说明: 1. **Android内存模型**:了解Android系统的内存...

    17个C++代码优化技巧

    以下是基于给定内容的一些C++代码优化技巧: 1. **确定浮点型变量和表达式类型**: 当涉及到浮点计算时,确保变量和表达式明确为`float`类型,特别是对于支持特定指令集(如3DNow!或SSE)的编译器,这将生成更高效...

    Flash优化技巧整理

    ### Flash优化技巧整理 #### 一、Flash游戏中ActionScript代码优化 **1、脚本运行速度的检测:getTimer();** - **getTimer()**: 使用`getTimer()`方法可以测量脚本的运行时间,这对于评估特定操作的效率非常有用...

    性能优化分享

    可以通过减少组件数量或者使用更轻量的设计模式来降低内存消耗。 - **事件代理**:为了减少事件监听器的数量,可以将事件处理逻辑集中在一个父级元素上,从而减少内存占用。 3. **图片优化**: - **懒加载**:只...

    论程序底层优化的一些方法与技巧.ppt

    本讲座由成都七中的骆可强分享了一些程序底层优化的方法与技巧,旨在帮助开发者提升程序的时间效率和空间效率。 首先,我们讨论的是算法的重要性。在程序设计中,时间效率通常用大O符号(O())来表示,它描述了函数...

    软件工程与软件性能优化技巧.pptx

    ### 软件工程与软件性能优化技巧 #### 第1章 软件性能优化概述 **软件性能优化定义:** 软件性能优化是指通过对软件系统的设计、实现和部署等方面的改进来提升系统的性能,包括但不限于响应速度、吞吐量以及并发...

    Oracle性能优化技巧

    Oracle性能优化技巧是数据库管理员和开发人员关注的重要领域,它涉及到如何提高SQL查询效率,减少资源消耗,从而...了解并应用这些优化技巧,能够显著提升Oracle数据库的性能和响应速度,降低系统负载,提升用户体验。

    App开发高级优化技巧

    在App开发过程中,高级优化技巧是提升应用性能、用户体验以及资源效率的关键。本文将深入探讨Java语言在App开发中的高级优化策略,旨在帮助开发者构建更高效、流畅的应用。 1. **代码优化** - **避免冗余计算**:...

    java优化编程 java优化编程 java优化编程

    Java优化编程是提升Java应用程序性能的关键技术,涵盖了多个方面的知识,包括代码优化...通过深入理解并实践这些Java优化编程技巧,开发者可以显著提升应用程序的运行效率,减少资源消耗,提高系统的稳定性和可扩展性。

Global site tag (gtag.js) - Google Analytics