本节介绍

  • Java堆的OutOfMemoryError测试
  • Eclipse Memory Analyzer分析内存溢出
  • 虚拟机栈和本地方法栈StackOverflowError测试
  • 方法区和运行时常量池溢出
  • 本机直接内存溢出

一、Java堆的OutOfMemoryError测试

  (1)首先设置debug configuration。如下图所示:

  (2)接下来进行编码操作,如下面的代码所示,不断添加新的对象到List中。由于Java堆设置的大小为20M并且不可扩展(将堆的最小值-Xms参数与最大值-Xmx参数设置为一样即可避免堆自动扩展),通过参数-XX:+HeapDumpOnOutOfMemoryError可以让虚拟机出现内存溢出异常时Dump出当前的内存堆转储快照以便事后进行分析。

  Java堆内存溢出测试:如下如所示: 

  

  (3)结果分析:Java堆内存的OOM(OutOfMemoryError)异常是实际应用中常见的内存溢出异常情况。当出现Java堆内存溢出时,异常堆栈信息“java.lang.OutOFMemoryError”会跟着进一步提示“Java heap space”

  

二、Eclipse Memory Analyzer分析内存溢出

   (1) Eclipse安装Eclipse Memory Analyzer。

      现在已经出1.2.1了,下载地址http://www.eclipse.org/mat/downloads.php

      也可以通过eclipse install new software ,地址http://download.eclipse.org/mat/1.2/update-site/

   (2)打开进入后,如下所示:

     要解决这个区域的异常,一般的手段是先通过内存映像工具(如Eclipse Memory Analyzer)对Dump出来的堆转储快照进行分析,重点是确认内存中的对象是否都是必要的,也就是要先分清楚到底是出现了内存泄露还是内存溢出。

    

    从上图可以看到它的大部分功能。
         1. Histogram可以列出内存中的对象,对象的个数以及大小。
         2. Dominator Tree可以列出那个线程,以及线程下面的那些对象占用的空间。
         3.Top consumers通过图形列出最大的object。
         4.Leak Suspects通过MA自动分析泄漏的原因。

   (3)这次重点是看Leak Suspects,点开后就能看到:

    

       

   (4)结果分析:在这张图上,我们可以清楚的看到,这个对象集合中保存了大量YourBeauty对象的引用,就是它导致的内存泄露。

三、虚拟机栈和本地方法栈StackOverflowError测试

   (1)如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。

  (2)如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。 
  (3)使用-Xss参数减小栈内存容量。测试结果:抛出StackOverflowError异常。异常出现时输出堆栈深度相应减小。
  
  
  (4) 实验表明:在单线程情况下,无论是由于栈帧太大还是虚拟机栈容量太小,当内存无法分配的时候,虚拟机抛出的都是StackOverflowError异常。

四、方法区和运行时常量池溢出

  (1)由于运行时常量池是方法区的一部分,因此这两个区域的溢出测试就放在了一起进行。前面提到JDK 1.7开始逐步“去永久代”的事情,在此就以测试代码观察一下这件事对程序的实际影响。

    

   (2)String.intern()是一个Native方法,它的作用是:如果字符串常量池已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象;否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。在JDK1.6及之前的版本中,由于常量池分配中永久代内,我们可以通过-XX:PermSize和-XX:MaxPermSize限制方法区大小,从而间接限制其中常量池的容量。

  

五、本机直接内存溢出

  (1) DirectMemory容量可通过-XX:MaxDirectMemorySize指定,如果不知道,则默认与Java堆最大值(-Xmx指定)一样,下述代码越过了DirectByteBuffer类,直接通过反射获取Unsafe实例进行内存分配。因为,虽然使用DirectByteBuffer分配内存也会抛出内存溢出异常,但它抛出异常时并没有真正向操作系统申请分配内存,而是同计算得知内存无法分配,于是手动抛出异常,真正申请分配内存的方法是unsafe.allocateMemory()

  

  (2)使用unsafe分配本机内存。

  

 

根据GC的工作原理,我们可以通过一些技巧和方式,让GC运行更加有效率,更加符合应用程序的要求。以下就是一些程序设计的几点建议。

1.最基本的建议就是尽早释放无用对象的引用。大多数程序员在使用临时变量的时候,都是让引用变量在退出活动域(scope)后,自动设置为null.我们在使用这种方式时候,必须特别注意一些复杂的对象图,例如数组,队列,树,图等,这些对象之间有相互引用关系较为复杂。对于这类对象,GC回收它们一般效率较低。如果程序允许,尽早将不用的引用对象赋为null.这样可以加速GC的工作。

2.尽量少用finalize函数。finalize函数是Java提供给程序员一个释放对象或资源的机会。但是,它会加大GC的工作量,因此尽量少采用finalize方式回收资源。

3.如果需要使用经常使用的图片,可以使用soft应用类型。它可以尽可能将图片保存在内存中,供程序调用,而不引起OutOfMemory.

4.注意集合数据类型,包括数组,树,图,链表等数据结构,这些数据结构对GC来说,回收更为复杂。另外,注意一些全局的变量,以及一些静态变量。这些变量往往容易引起悬挂对象(dangling reference),造成内存浪费。

5.当程序有一定的等待时间,程序员可以手动执行System.gc(),通知GC运行,但是Java语言规范并不保证GC一定会执行。使用增量式GC可以缩短Java程序的暂停时间。

深入理解 Java 虚拟机之学习笔记(2)的更多相关文章

  1. Java四种引用--《深入理解Java虚拟机》学习笔记及个人理解(四)

    Java四种引用--<深入理解Java虚拟机>学习笔记及个人理解(四) 书上P65. StrongReference(强引用) 类似Object obj = new Object() 这类 ...

  2. Java虚拟机内存溢出异常--《深入理解Java虚拟机》学习笔记及个人理解(三)

    Java虚拟机内存溢出异常--<深入理解Java虚拟机>学习笔记及个人理解(三) 书上P39 1. 堆内存溢出 不断地创建对象, 而且保证创建的这些对象不会被回收即可(让GC Root可达 ...

  3. 【Java】「深入理解Java虚拟机」学习笔记(1) - Java语言发展趋势

    0.前言 从这篇随笔开始记录Java虚拟机的内容,以前只是对Java的应用,聚焦的是业务,了解的只是语言层面,现在想深入学习一下. 对JVM的学习肯定不是看一遍书就能掌握的,在今后的学习和实践中如果有 ...

  4. 《深入理解Java虚拟机》学习笔记

    <深入理解Java虚拟机>学习笔记 一.走近Java JDK(Java Development Kit):包含Java程序设计语言,Java虚拟机,JavaAPI,是用于支持 Java 程 ...

  5. 《深入理解 Java 虚拟机》学习笔记 -- 内存区域

    <深入理解 Java 虚拟机>学习笔记 -- 内存区域 运行时数据区域 主要分为 6 部分: 程序计数器 虚拟机栈 本地方法栈 Java 堆 方法区 如图所示: 1. 程序计数器(线程私有 ...

  6. 《深入理解java虚拟机》学习笔记之编译优化技术

    郑重声明:本片博客是学习<深入理解Java虚拟机>一书所记录的笔记,内容基本为书中知识. Java程序员有一个共识,以编译方式执行本地代码比解释方式更快,之所以有这样的共识,除去虚拟机解释 ...

  7. 《深入理解java虚拟机》学习笔记之虚拟机即时编译详解

    郑重声明:本片博客是学习<深入理解java虚拟机>一书所记录的笔记,内容基本为书中知识. Java程序最初是通过解释器(Interpreter)进行解释执行的,当虚拟机发现某个方法或代码块 ...

  8. 《深入理解 java虚拟机》学习笔记

    java内存区域详解 以下内容参考自<深入理解 java虚拟机 JVM高级特性与最佳实践>,其中图片大多取自网络与本书,以供学习和参考.

  9. 《深入理解Java虚拟机》学习笔记之类加载

    之前在学习ASM时做了一篇笔记<Java字节码操纵框架ASM小试>,笔记里对类文件结构做了简介,这里我们来回顾一下. Class类文件结构 在Java发展之初设计者们发布规范文档时就刻意把 ...

  10. Java虚拟机运行时栈帧结构--《深入理解Java虚拟机》学习笔记及个人理解(二)

    Java虚拟机运行时栈帧结构(周志明书上P237页) 栈帧是什么? 栈帧是一种数据结构,用于虚拟机进行方法的调用和执行. 栈帧是虚拟机栈的栈元素,也就是入栈和出栈的一个单元. 2018.1.2更新(在 ...

随机推荐

  1. Java 语法糖详解

    语法糖 语法糖(Syntactic Sugar),也称糖衣语法,是由英国计算机学家 Peter.J.Landin 发明的一个术语,指在计算机语言中添加的某种语法. 这种语法对语言的功能并没有影响,但是 ...

  2. goto语句引起的crosses initialization of XXX

    1. 背景 goto语句虽然目前已经不提倡使用,但是用起来还是很方便,尤其是老代码中见的比较多. 在改动有goto语句的老代码时需要特别注意,是否跳过来资源的释放.有用变量的初始化等等. 很久之前写c ...

  3. [Python设计模式] 第8章 学习雷锋好榜样——工厂方法模式

    github地址:https://github.com/cheesezh/python_design_patterns 简单工厂模式 v.s. 工厂方法模式 以简单计算器为例,对比一下简单工厂模式和工 ...

  4. ios mac 对照片进行JPEG压缩

    ios mac 对照片进行JPEG压缩 1. 在iOS上可以使用 API UIImageJPEGRepresentation 对照片数据进行JPEG压缩: 我们知道iOS其实是MAC OS 的移植,那 ...

  5. 常用CTPN、CRNN文本检测识别框架

    一.SWT识别: yestinsong/Text-Detection( Text Detection System with MSER , SWT and Text Verification(fft ...

  6. android中webView加载H5,JS不能调用问题的解决

    使用了html5 页面,使用webView加载后发现 超链接的锚点不可以用 为webView设置下面两句就好了: mWebView.getSettings().setDomStorageEnabled ...

  7. golang ----gc问题

    go程序内存占用大的问题 这个问题在我们对后台服务进行压力测试时发现,我们模拟大量的用户请求访问后台服务,这时各服务模块能观察到明显的内存占用上升.但是当停止压测时,内存占用并未发生明显的下降.花了很 ...

  8. Android UI系列-----CheckBox和RadioButton(1)

    主要记录一下CheckBox多选框和RadioGroup.RadioButton单选框的设置以及注册监听器 1.CheckBox 布局文件: <LinearLayout xmlns:androi ...

  9. Vue 温故而知新 props如何双向属性绑定

    传送门:https://cn.vuejs.org/v2/guide/components-custom-events.html https://segmentfault.com/q/101000001 ...

  10. 入门:移动APP中的各种导航

    即使是移动应用界面的原型设计,导航的形式也可以多种多样.尽管尺寸小,又必须紧凑排列大量数据,它们似乎受到了紧密的约束,但依然有着形形色色的选择. 人们曾经一度只会考虑一种形式——流行且广泛使用的垂直导 ...