近期看了看Java内存泄露的一些案例,跟原来的几个哥们讨论了一下,深入研究发现JVM里面还是有不少以前不知道的细节,这里稍微剖析一下。先看一看JVM的内部结构——
如图所示,JVM主要包括两个子系统和两个组件。两个子系统分别是Class loader子系统和Execution engine(执行引擎) 子系统;两个组件分别是Runtime data area (运行时数据区域)组件和Native interface(本地接口)组件。
Class loader子系统的作用:根据给定的全限定名类名(如 java.lang.Object)来装载class文件的内容到 Runtime data area中的method area(方法区域)。Java程序员可以extends java.lang.ClassLoader类来写自己的Class loader。
Execution engine子系统的作用:执行classes中的指令。任何JVM specification实现(JDK)的核心都是Execution engine,不同的JDK例如Sun 的JDK 和IBM的JDK好坏主要就取决于他们各自实现的Execution engine的好坏。
Native interface组件:与native libraries交互,是其它编程语言交互的接口。当调用native方法的时候,就进入了一个全新的并且不再受虚拟机限制的世界,所以也很容易出现JVM无法控制的native heap OutOfMemory。
Runtime Data Area组件:这就是我们常说的JVM的内存了。它主要分为五个部分——
1、Heap (堆):一个Java虚拟实例中只存在一个堆空间
2、Method Area(方法区域):被装载的class的信息存储在Method area的内存中。当虚拟机装载某个类型时,它使用类装载器定位相应的class文件,然后读入这个class文件内容并把它传输到虚拟机中。
3、Java Stack(java的栈):虚拟机只会直接对Java stack执行两种操作:以帧为单位的压栈或出栈
4、Program Counter(程序计数器):每一个线程都有它自己的PC寄存器,也是该线程启动时创建的。PC寄存器的内容总是指向下一条将被执行指令的饿地址,这里的地址可以是一个本地指针,也可以是在方法区中相对应于该方法起始指令的偏移量。
5、Native method stack(本地方法栈):保存native方法进入区域的地址
以上五部分只有Heap 和Method Area是被所有线程的共享使用的;而Java stack, Program counter 和Native method stack是以线程为粒度的,每个线程独自拥有自己的部分。
了解JVM的系统结构,再来看看JVM内存回收问题了——
Sun的JVM Generational Collecting(垃圾回收)原理是这样的:把对象分为年青代(Young)、年老代(Tenured)、持久代(Perm),对不同生命周期的对象使用不同的算法。(基于对对象生命周期分析)
如上图所示,为Java堆中的各代分布。
1. Young(年轻代)
年轻代分三个区。一个Eden区,两个Survivor区。大部分对象在Eden区中生成。当Eden区满时,还存活的对象将被复制到Survivor区(两个中的一个),当这个Survivor区满时,此区的存活对象将被复制到另外一个Survivor区,当这个Survivor去也满了的时候,从第一个Survivor区复制过来的并且此时还存活的对象,将被复制年老区(Tenured。需要注意,Survivor的两个区是对称的,没先后关系,所以同一个区中可能同时存在从Eden复制过来 对象,和从前一个Survivor复制过来的对象,而复制到年老区的只有从第一个Survivor去过来的对象。而且,Survivor区总有一个是空的。
2. Tenured(年老代)
年老代存放从年轻代存活的对象。一般来说年老代存放的都是生命期较长的对象。
3. Perm(持久代)
用于存放静态文件,如今Java类、方法等。持久代对垃圾回收没有显著影响,但是有些应用可能动态生成或者调用一些class,例如Hibernate等,在这种时候需要设置一个比较大的持久代空间来存放这些运行过程中新增的类。持久代大小通过-XX:MaxPermSize=进行设置。
举个例子:当在程序中生成对象时,正常对象会在年轻代中分配空间,如果是过大的对象也可能会直接在年老代生成(据观测在运行某程序时候每次会生成一个十兆的空间用收发消息,这部分内存就会直接在年老代分配)。年轻代在空间被分配完的时候就会发起内存回收,大部分内存会被回收,一部分幸存的内存会被拷贝至Survivor的from区,经过多次回收以后如果from区内存也分配完毕,就会也发生内存回收然后将剩余的对象拷贝至to区。等到to区也满的时候,就会再次发生内存回收然后把幸存的对象拷贝至年老区。
通常我们说的JVM内存回收总是在指堆内存回收,确实只有堆中的内容是动态申请分配的,所以以上对象的年轻代和年老代都是指的JVM的Heap空间,而持久代则是之前提到的Method Area,不属于Heap。
了解完这些之后,以下的转载一热衷于钻研技术的哥们Richen Wang关于内存管理的一些建议——
1、手动将生成的无用对象,中间对象置为null,加快内存回收。
2、对象池技术 如果生成的对象是可重用的对象,只是其中的属性不同时,可以考虑采用对象池来较少对象的生成。如果有空闲的对象就从对象池中取出使用,没有再生成新的对象,大大提高了对象的复用率。
3、JVM调优 通过配置JVM的参数来提高垃圾回收的速度,如果在没有出现内存泄露且上面两种办法都不能保证内存的回收时,可以考虑采用JVM调优的方式来解决,不过一定要经过实体机的长期测试,因为不同的参数可能引起不同的效果。如-Xnoclassgc参数等。
推荐的两款内存检测工具
1、jconsole JDK自带的内存监测工具,路径jdk bin目录下jconsole.exe,双击可运行。连接方式有两种,第一种是本地方式如调试时运行的进程可以直接连,第二种是远程方式,可以连接以服务形式启动的进程。远程连接方式是:在目标进程的jvm启动参数中添加-Dcom.sun.management.jmxremote.port=1090 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false 1090是监听的端口号具体使用时要进行修改,然后使用IP加端口号连接即可。通过该工具可以监测到当时内存的大小,CPU的使用量以及类的加载,还提供了手动gc的功能。优点是效率高,速度快,在不影响进行运行的情况下监测产品的运行。缺点是无法看到类或者对象之类的具体信息。使用方式很简单点击几下就可以知道功能如何了,确实有不明白之处可以上网查询文档。
2、JProfiler 收费的工具,但是到处都有破解办法。安装好以后按照配置调试的方式配置好一个本地的session即可运行。可以监测当时的内存、CPU、线程等,能具体的列出内存的占用情况,还可以就某个类进行分析。优点很多,缺点太影响速度,而且有的类可能无法被织入方法,例如我使用jprofiler时一直没有备份成功过,总会有一些类的错误。
- 大小: 15.4 KB
- 大小: 73.5 KB
分享到:
相关推荐
JVM 内存溢出问题解析 JVM 内存溢出是指程序运行所需的内存大于虚拟机能提供的最大内存的情况。这种情况可能是由于数据量过大、死循环、静态变量和静态方法过多、递归、无法确定是否被引用的对象等原因引起的。同时...
《深入理解IDEA插件JProfiler11:高效优化JVM内存》 在Java开发领域,高效运行和优化JVM内存是至关重要的。IntelliJ IDEA(简称Idea)作为广受欢迎的Java集成开发环境,提供了一系列强大的工具来帮助开发者进行性能...
### JVM内存空间分配详解 #### 一、JVM内存模型概览 JVM(Java虚拟机)内存模型主要由以下几个部分组成:程序计数器、Java虚拟机栈、本地方法栈、Java堆以及方法区(在JDK 8之后称为元空间)。下面将对这几个部分...
MAT JVM内存分析工具可以帮助开发者深入理解Java虚拟机(JVM)的内存管理机制,通过分析堆内存快照来识别内存消耗异常的情况。 首先,MAT提供了丰富的视图来帮助用户查看内存状态,例如“概述”视图可以快速了解堆...
总之,MAT作为一款强大的JVM内存分析工具,对于优化Java应用的内存使用,提升应用性能,尤其是对于Mac OS X平台的开发者来说,是不可或缺的利器。通过熟练掌握MAT的使用,开发者可以更有效地管理和优化应用程序的...
JVM内存管理主要包括内存结构、内存分配以及垃圾回收(GC)等方面。了解这些知识对于优化Java应用程序的性能至关重要。 ### 1. JVM内存结构 #### 1.1.1 JVM内存概述 JVM内存分为几个关键区域,每个区域都有特定的...
在这份由Sun Microsystems公司出版的《JVM内存管理白皮书》中,我们可以找到关于Java虚拟机(JVM)内存管理的详细介绍和深入分析。这份文档对于想要深入了解JVM工作原理的读者来说是一份宝贵的学习资料。在这份...
### JVM内存配置优化 #### 一、理解JVM内存模型 在进行JVM内存配置优化之前,我们需要了解Java虚拟机(JVM)的内存结构。Java的逻辑内存模型大致分为几个部分: 1. **堆内存(Heap)**:主要用于存储对象实例、数组...
JVM内存模型深度剖析与优化 JVM内存模型是Java虚拟机的核心组件之一,它直接影响着Java应用程序的性能和可靠性。本文将深入剖析JVM内存模型的结构和工作机理,并讨论如何优化JVM参数以提高Java应用程序的性能。 一...
本文将深入探讨如何在Java中获取JVM内存大小,包括堆内存的总量、最大值以及剩余空间,并解析给定代码片段中的关键概念。 ### JVM内存模型 在讨论如何获取JVM内存大小之前,首先需要理解JVM的内存布局。JVM内存...
### JVM内存监控工具详解 #### 引言 Java Virtual Machine (JVM) 是运行 Java 应用程序的核心组件,其性能直接影响应用的响应速度和稳定性。JVM 的内存管理是性能优化的关键,尤其是在高并发环境下,合理的内存...
在JVM内存管理中,内存泄漏是一种常见的性能问题,可能导致应用运行缓慢,甚至崩溃。MAT通过解析JVM生成的hprof文件(内存快照),可以深入分析堆内存的各个部分,包括对象分配、存活状态、引用关系等,帮助定位问题...
该文档描述了开发测试环境中Docker及JVM内存限制部署方案
在开发和优化Java应用程序时,理解JVM内存日志至关重要,因为它可以帮助我们诊断性能问题,例如内存泄漏或过度的垃圾收集。`jmap`是Java的一个命令行工具,用于获取堆内存的详细信息,包括堆dump,这对于分析JVM内存...
1. **JVM内存结构** JVM内存主要分为以下几个区域: - **方法区(Method Area)**:这是所有线程共享的区域,存储类信息、常量、静态变量、即时编译后的代码等。在Java 8以前,这部分也被称为永久代(Permanent ...
JVM 内存参数详解以及配置调优 JVM 内存参数是 Java 虚拟机中最重要的参数之一,它直接影响着 Java 应用程序的性能和稳定性。在这个资源中,我们将详细讨论 JVM 内存参数的配置和调优,包括 JVM 的结构、内存管理、...
MAT,全称Memory Analyzer Tool,是IBM开发的一款强大的JVM内存分析工具,尤其适用于诊断Java应用程序的内存泄漏问题。在Java开发过程中,内存溢出(Out Of Memory)问题常常会导致程序异常终止,而MAT就是解决这类...
本资料总结主要关注JVM内存分配及其运行原理,这对于理解和优化Java应用程序的性能至关重要。 1. **JVM内存结构** JVM内存分为几个关键区域:方法区(Method Area)、堆(Heap)、栈(Stack)、程序计数器(PC ...
### JVM内存结构详解 #### 一、概述 Java虚拟机(JVM)作为Java程序的运行环境,其核心组件之一便是内存管理系统。理解JVM的内存布局对于开发高性能的应用程序至关重要。本文将详细介绍JVM内存结构及其各个组成部分...