`

JAVA内存释放机制

    博客分类:
  • JAVA
阅读更多
和内存释放(主要是GC)有关的话题。

  ★JVM的内存?
  在Java虚拟机规范中(具体章节请看“这里 ”),提及了如下几种类型的内存空间:
  ◇栈内存(Stack):每个线程私有的。
  ◇堆内存(Heap):所有线程公用的。
  ◇方法区(Method Area):有点像以前常说的“进程代码段”,这里面存放了每个加载类的反射信息、类函数的代码、编译时常量等信息。
  ◇原生方法栈(Native Method Stack):主要用于JNI中的原生代码,平时很少涉及。
?
  ★垃圾回收机制简介?
  其实Java虚拟机规范中并未规定垃圾回收的相关细节。垃圾回收具体该怎么搞,完全取决于各个JVM的设计者。所以,不同的JVM之间,GC的行为可能会有一定的差异。下面咱拿SUN官方的JVM来简单介绍 一下GC的机制。
  ◇啥时候进行垃圾回收?
  一般情况下,当JVM发现堆内存比较紧张、不太够用时,它就会着手进行垃圾回收工作。但是大伙儿要认清这样一个残酷的事实:JVM进行GC的时间点是无法精确预知的。因为GC启动的时刻会受到各种运行环境因素的影响,随机性太大。
  虽说咱们无法精确预知,但假如你想知道每次垃圾回收执行的情况,还是蛮方便的。可以通过JVM的命令行参数“-XX:+PrintGC”把相关信息打印出来。
   另外,调用System.gc()只是建议JVM进行GC。至于JVM到底会不会做,那就不好说啦。通常不建议自己手动调用System.gc(),还 是让JVM自行决定比较好。另外,使用JVM命令行参数“-XX:+DisableExplicitGC”可以让System.gc()不起作用。
  ◇谁来负责垃圾回收?
  一般情况下,JVM会有一个或多个专门的垃圾回收线程,由它们负责清理回收垃圾内存。
  ◇如何发现垃圾对象?
  垃圾回收线程会从“根集(Root Set)”开始进行对象引用的遍历。所谓的“根集”,就是正在运行的线程中,可以访问的引用变量 的 集合(比如所有线程当前函数的参数和局部变量、当前类的成员变量等等)。垃圾回收线程先找出被根集直接引用的所有对象(不妨叫集合1),然后再找出被集合 1直接引用的所有对象(不妨叫集合2),然后再找出被集合2直接引用的所有对象......如此循环往复,直到把能遍历到的对象都遍历完。
  凡是从根集通过上述遍历可以到达的对象,都称为可达对象或有效对象;反之,则是不可达对象或失效对象(也就是垃圾)。
  ◇如何清理/回收垃圾?
  通过上述阶段,就把垃圾对象都找出来。然后垃圾回收线程会进行相应的清理和回收工作,包括:把垃圾内存重新变为可用内存、进行内存的整理以消除内存碎片、等等。这个过程会涉及到若干算法,有爱好的同学可以参见“这里 ”。限于篇幅,咱就不深入聊了。
  ◇分代
   早期的JVM是不采用分代技术的,所有被GC管理的对象都存放在同一个堆里面。这么做的缺点比较明显:每次进行GC都要遍历所有对象,开销很大。其实大 部分的对象生命周期都很短(短命对象),只有少数对象比较长寿;在这些短命对象中,又只有少数对象占用的内存空间大;其它大量的短命对象都属于小对象(很 符合二八原理 )。
   有鉴于此,从JDK 1.2之后,JVM开始使用分代的垃圾回收(Generational Garbage Collection)。JVM把GC相关的内存分为年老代(Tenured)和年轻代(Nursery)、持久代(Permanent,对应于JVM规 范的方法区)。大部分 对象在刚创建时,都位于年轻代。假如某对象经历了几轮GC还活着(大龄对象),就把它移到年老代。另外,假如某个对象在创建时比较大,可能就直接被丢到年老代。经过这种策略,使得年轻代总是保存那些短命的小对象。在空间尺寸上,年轻代相对较小,而年老代相对较大。
  因为有了分代技术,JVM的GC也相应分为两种:主要收集(Major Collection)和次要收集(Minor Collection)。主要收集同时清理年老代和年轻代,因此开销很大,不常进行;次要收集仅仅清理年轻代,开销很小,经常进行。
?
  ★GC对性能会有啥影响??
  刚才介绍了GC的大致原理,那GC对性能会造成哪些影响捏?主要有如下几个方面:
  ◇造成当前运行线程的停顿
  早期的GC比较弱智。在它工作期间,所有其它的线程都被暂停(以免影响垃圾回收工作)。等到GC干完活,其它线程再继续运行。所以,早期JDK的GC一旦开始工作,整个程序就会陷入假死状态,失去各种响应。
  经过这些年的技术改进(包括采用分代技术),从JDK 1.4开始,GC已经比较精明了。在它干活期间,只是偶然暂停一下其它线程的运行(从长时间假死变为暂时性休克)。
  ◇遍历对象引用的开销
  试想假如JVM中的对象很多,那遍历完所有可达对象肯定是比较费劲的工作,这个开销可不小。
  ◇清理和回收垃圾的开销
  遍历完对象引用之后,对垃圾的清理和回收也有较大的开销。这部分开销可能包括复制内存块、更新对象引用等等。
?
  ★几种收集器?
  ◇两个性能指标
  因为今天聊的是性能的话题,必然会提到衡量GC性能的两个重要指标:吞吐量(Throughput)和停顿时间(Pause Time)。吞吐量这个词不是很直观,解释一下:就是JVM不用于 GC的时间占总时间的比率。吞吐量是越大越好,停顿时间是越小越好。
  不同的应用程序对这两个指标的关注点不一样(后面具体会说),也就是所谓的“众口难调”。很多JVM厂商为了迎合“众口”,不得不提供多种几种垃圾收集器供使用者选择。不同的收集器,采用的收集策略是不一样的,下面具体介绍。
  ◇串行收集器(Serial Collector)
  使用命令行选项“-XX:+UseSerialGC”指定。
  这种收集器是最传统的收集器。它使用单线程进行垃圾回收,对于单CPU机器比较合适。另外,小型应用或者对上述两个指标没有非凡要求的,可以使用串行收集器。
  ◇并行收集器(Parallel Throughput Collector)
  顾名思义,这种收集器使用多个线程进行垃圾回收以达到高吞吐量。垃圾回收线程的数量通过命令行选项“-XX:ParallelGCThreads=n”指定。可以设置该数值以便充分利用多CPU/多核。
  当使用命令行选项“-XX:+UseParallelGC”时:它会针对年轻代使用多个垃圾回收线程,对年老代依然使用单个线程的串行方式。此选项最早在JDK 1.5引入。
  当使用命令行选项“-XX:+UseParallelOldGC”时:它针对年轻代和年老代都使用多个垃圾回收线程的方式。不过此选项从JDK 1.6才开始引入。
  ◇并发收集器(Concurrent Low Pause Collector)
  使用命令行选项“-XX:+UseConcMarkSweepGC”指定。
  这种收集器优先保证程序的响应。它会尽量让垃圾回收线程和应用自身的线程同时运行,从而降低停顿时间。此选项从JDK 1.4.1开始支持。
  ◇增量收集器(Incremental Collector)
  自从JDK 1.4.2以来,SUN官方就停止维护该收集器了。所以俺就节省点口水,不多说了。
?
  ★如何降低GC的影响??
  ◇尽量减少堆内存的使用
  由于GC是针对存储在堆内存的对象进行的。咱们假如在程序中减少引用对象的分配(也就相应降低堆内存分配),那对于提高GC的性能是很有帮助滴。上次“字符串过滤实战 ”的帖子给出了一个例子,示范了如何通过降低堆内存的分配次数来提升性能。
?
  ◇设置合适的堆内存大小
  JVM的堆内存是有讲究的,不能太大也不能太小。假如堆内存太小,JVM老是感觉内存不够用,可能会导致频繁进行垃圾回收,影响了性能;假如堆内存太大,以至于操作系统的大部分物理内存都被JVM自个儿霸占了,那可能会影响其它应用程序甚至操作系统本身的性能。
  另外,年轻代的大小(或者说年轻代与年老代的比值)对于GC的性能也有明显影响。假如年轻代太小,可能导致次要收集很频繁;假如年轻代太大,导致次要收集的停顿很明显。
  JVM提供了若干和堆内存大小相关的命令行选项,具体如下:
------------------------------
-Xms  设置初始堆内存
-Xmx  设置最大堆内存
-Xmn  设置年轻代的大小
-XX:NewRatio=n  设置年轻代与年老代的比例为“n”
-XX:NewSize=n  设置年轻代大小为“n”
------------------------------
  一般情况下,JVM的默认参数值已经够用。所以没事儿别轻易动用上述选项。假如你非调整不可,一定要做深入的性能对比测试,保证调整后的性能确实优于默认参数值。
?
  ◇吞吐量和停顿的取舍
  前面提到了不同应用的众口难调。常见的口味有两种:(1)看重吞吐量,对停顿时间无所谓;(2)侧重于停顿时间。
  对于某些在后台的、单纯运算密集型的应用,属于第一种。比如某些科学计算的应用。这时候建议使用并行收集器。
  对于涉及用户UI交互的、实时性要求比较高、程序需要快速响应的,属于第二种。比如某些桌面游戏、某些电信交换系统。这时候建议使用并发收集器。
?
  ★相关的参考资料?
  ◇GC调优资料
  SUN官方提供了若干关于JVM垃圾回收调优的说明文档,JDK 1.4.2请看“这里 ”;JDK 1.5请看“这里 ”;JDK 1.6请看“这里 ”。
  ◇JVM命令行选项说明
  这是SUN公司内的某个有心人整理的各种命令行参数大全,在“这里 ”。包括有每个参数所适用的JDK版本。
  ◇虚拟机规范
  “这里 ”是SUN官方的JVM规范。
分享到:
评论

相关推荐

    java内存分配机制详解

    ### Java内存分配机制详解 #### 一、引言 Java作为一种广泛应用的编程语言,其内存管理机制对于确保程序高效稳定运行至关重要。本文旨在详细介绍Java内存分配机制中的几个关键概念:寄存器、栈、堆、静态域、常量...

    Java的内存管理机制分析

    通过对Java内存管理机制的深入分析,我们可以了解到Java如何高效地管理和利用内存资源。理解这些机制对于优化Java应用程序的性能至关重要,特别是在处理大规模数据集或多线程环境时。此外,合理配置JVM参数和选择...

    java管理windows系统内存_java释放内存缓存_java获得CPU使用率_系统内存_硬盘_进程源代码

    "java管理windows系统内存_java释放内存缓存_java获得CPU使用率_系统内存_硬盘_进程源代码" 在Windows操作系统中,内存管理是一个非常重要的方面。Windows实现按需调页的虚拟内存机制,使得应用程序可以使用超过...

    java内存泄漏解决

    ### Java内存泄漏解决方案详解 #### 一、Java内存泄漏概述 在Java开发过程中,经常会遇到内存泄漏的问题,尤其是在长时间运行的应用程序中更为常见。本文将详细介绍如何解决Java内存泄漏问题,帮助开发者更好地...

    java内存原理.doc

    Java 中的内存管理机制是自动的,开发者不需要手动释放内存,但是这也使得 Java 程序占用内存相对较高。为了避免内存泄露,开发者需要注意在编写程序时,合理地使用内存资源。 Java 内存原理的优点: * 自动内存...

    Java 内存模型

    Java内存模型是Java虚拟机规范中定义的一部分,它规定了Java程序中变量的读写行为,以及线程之间的交互规则。理解Java内存模型对于编写正确、高效的多线程程序至关重要。在Java 5之前,Java内存模型的描述比较模糊,...

    如何解决Java内存泄漏

    Java内存回收机制 Java的内存管理主要集中在堆(Heap)区域,其中对象的创建通常是通过`new`关键字或反射方式完成,而对象的释放则由Java虚拟机(JVM)通过垃圾回收(GC)机制自动处理。对象回收的基本原则是:当一个...

    Java的内存机制

    1. **Java内存管理** - **内存分配**:在Java中,内存的分配主要由程序通过`new`关键字来完成。对象都分配在堆内存(Heap)中,而基本数据类型(如int, short, long, byte, float, double, boolean, char)的实例则...

    易语言内存释放

    "易语言内存释放"这个主题主要涉及到程序运行过程中动态分配和释放内存的过程。本文将深入探讨易语言中的内存管理,特别是内存释放及其相关的技术。 易语言是中国本土开发的一种编程语言,其设计目标是让编程变得...

    Java数组与内存控制

    ### Java数组与内存控制 #### 一、Java数组在内存分配方面的知识 ##### 1.1 数组初始化 - **声明数组的时候如何分配内存:** - 在Java中,数组的...理解Java数组及其内存管理机制对于高效编写Java程序至关重要。

    java内存管理问题及解决办法

    本文将深入探讨Java内存管理机制,包括垃圾回收、内存分配与释放、内存泄漏及其预防措施,以及四种引用类型的特点和应用场景。 首先,Java内存分为堆内存(Heap)和栈内存(Stack)。堆内存主要用于存储对象实例,...

    Java 内存区域和GC机制

    Java内存区域和垃圾收集(GC)机制是Java编程中至关重要的一部分,它关乎程序的性能、稳定性和资源管理。本文将深入探讨Java虚拟机(JVM)中的内存划分、垃圾收集的工作原理以及相关工具的使用。 1. **Java内存区域...

    Java内存泄露检测

    Java内存泄露检测是Java开发中一个关键的议题,因为它直接影响到程序的稳定性和资源效率。内存泄露是指程序中已分配的内存无法被正确地释放,从而导致系统资源的浪费和可能导致程序性能下降甚至崩溃。 首先,理解...

    java内存管理 ppt

    **垃圾收集(Garbage Collection, GC)**是Java内存管理的重要部分,其目标是自动识别并回收不再使用的对象,释放内存。Java提供多种垃圾收集算法,如标记-清除、复制、标记-整理和分代收集。其中,分代收集将堆内存...

    cpu 内存模型和java内存模型

    Java程序员了解CPU以及相关的内存模型,对于深入理解...通过分析具体的编程问题,比如Java锁的不同实现方式、CPU缓存的工作机制等,可以帮助程序员更好地理解Java内存模型,在多线程环境下写出更加健壮和高效的代码。

    java主要反射和内存机制

    **二、Java内存分配机制** Java的内存分配涉及到堆、栈、方法区、本地方法栈和程序计数器等几个区域: 1. **堆内存**:这是所有对象实例以及数组的存储区域。Java垃圾收集器主要负责清理堆中的无用对象。 2. **栈...

    JAVA内存溢出详解.doc

    总之,Java内存溢出是复杂的问题,需要结合程序设计、JVM参数配置、垃圾收集机制和内存分析工具等多个方面进行综合分析和处理。理解这些概念并熟练运用,能有效防止和解决Java应用程序中的内存问题。

    java实现内存动态分配

    Java 实现内存动态分配主要涉及Java内存模型以及内存管理机制,包括堆内存和栈内存的分配,以及垃圾回收等概念。下面将详细解释这些知识点。 1. **Java内存模型** Java程序运行时,内存分为堆内存(Heap)和栈内存...

    java内存分配情况

    Java内存分配主要涉及五个区域:寄存器、栈、堆、静态域和常量池。在Java编程中,理解这些内存区域的分配规则对于优化代码性能和避免内存泄漏至关重要。 1. **寄存器**:这是最快捷的存储区域,但不在Java程序员的...

Global site tag (gtag.js) - Google Analytics