Java体系结构---垃圾回收
1 垃圾回收
1.1 JVM的体系结构
1.1.1 JVM
相当与JAVA 的操作系统,是运行JAVA Class文件的程序。
1.1.2 JVM体系
监控调优,运行时内存结构,类加载,calss文件格式,GC
Java字节码和虚拟机执行引擎,线程安全和锁,java内存模型
1.2 JVM的类加载机制
1.2.1 加载过程
类从被加载到虚拟机内存中开始,到卸载出内存为止,它的生命周期包括了:加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)、卸载(Unloading)七个阶段,其中验证、准备、解析三个部分统称链接。
加载(装载)、验证、准备、初始化和卸载这五个阶段顺序是固定的,类的加载过程必须按照这种顺序开始,而解析阶段不一定;它在某些情况下可以在初始化之后再开始,这是为了运行时动态绑定特性(JIT例如接口只在调用的时候才知道具体实现的是哪个子类)。值得注意的是:这些阶段通常都是互相交叉的混合式进行的,通常会在一个阶段执行的过程中调用或激活另外一个阶段。
1.2.2 类加载器
JVM设计者把类加载阶段中的“通过'类全名'来获取定义此类的二进制字节流”这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类。实现这个动作的代码模块称为“类加载器”。
1.类与类加载器
对于任何一个类,都需要由加载它的类加载器和这个类来确立其在JVM中的唯一性。也就是说,两个类来源于同一个Class文件,并且被同一个类加载器加载,这两个类才相等。
2.双亲委派模型
从虚拟机的角度来说,只存在两种不同的类加载器:一种是启动类加载器(Bootstrap ClassLoader),该类加载器使用C++语言实现,属于虚拟机自身的一部分。另外一种就是所有其它的类加载器,这些类加载器是由Java语言实现,独立于JVM外部,并且全部继承自抽象类java.lang.ClassLoader。
从Java开发人员的角度来看,大部分Java程序一般会使用到以下三种系统提供的类加载器:
1)启动类加载器(Bootstrap ClassLoader):负责加载JAVA_HOME\lib目录中并且能被虚拟机识别的类库到JVM内存中,如果名称不符合的类库即使放在lib目录中也不会被加载。该类加载器无法被Java程序直接引用。
2)扩展类加载器(Extension ClassLoader):该加载器主要是负责加载JAVA_HOME\lib\,该加载器可以被开发者直接使用。
3)应用程序类加载器(Application ClassLoader):该类加载器也称为系统类加载器,它负责加载用户类路径(Classpath)上所指定的类库,开发者可以直接使用该类加载器,如果应用程序中没有自定义过自己的类加载器,一般情况下这个就是程序中默认的类加载器。
我们的应用程序都是由这三类加载器互相配合进行加载的,我们也可以加入自己定义的类加载器。这些类加载器之间的关系如下图所示:
1.2.3
双亲委派
双亲委派模型的工作过程为:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一个层次的加载器都是如此,因此所有的类加载请求都会传给顶层的启动类加载器,只有当父加载器反馈自己无法完成该加载请求(该加载器的搜索范围中没有找到对应的类)时,子加载器才会尝试自己去加载。
1.3
内存组成及分配
1.3.1
堆区与非堆区
“Java 虚拟机具有一个堆,堆是运行时数据区域,所有类实例和数组的内存均从此处分配。堆是在 Java 虚拟机启动时创建的。”“在JVM中堆之外的内存称为非堆内存(Non-heap memory)”。可以看出JVM主要管理两种类型的内存:堆和非堆。简单来说堆就是Java代码可及的内存,是留给开发人员使用的;非堆就是JVM留给
自己用的,所以方法区、JVM内部处理或优化所需的内存(如JIT编译后的代码缓存)、每个类结构(如运行时常数池、字段和方法数据)以及方法和构造方法
的代码都在非堆内存中。
- 方法栈&本地方法栈:
线程创建时产生,方法执行时生成栈帧 - 方法区
存储类的元数据信息 常量等 - 堆
java代码中所有的new操作 - native Memory(C heap)
Direct Bytebuffer JNI Compile GC;
1.3.2
堆内存分配
JVM初始分配的内存由-Xms指定,默认是物理内存的1/64;JVM最大分配的内存由-Xmx指 定,默认是物理内存的1/4。默认空余堆内存小于40%时,JVM就会增大堆直到-Xmx的最大限制;空余堆内存大于70%时,JVM会减少堆直到 -Xms的最小限制。因此服务器一般设置-Xms、-Xmx相等以避免在每次GC 后调整堆的大小。对象的堆内存由称为垃圾回收器的自动内存管理系统回收。
1.3.3
非堆内存分配
JVM使用-XX:PermSize设置非堆内存初始值,默认是物理内存的1/64;由XX:MaxPermSize设置最大非堆内存的大小,默认是物理内存的1/4。
1.4
垃圾回收
Java中不需要对内存进行手动释放,JVM中的垃圾回收器帮助我们回收内存。
1.4.1
何时回收
一般来说,当某个区域内存不够的时候就会进行垃圾回收。如:
当Eden区域分配不下对象时,就会进行年轻代的垃圾收集。
1.4.2
何如判断一块内存是垃圾
即判断一个对象不再被使用,不再使用可以是内有有效的引用。一般来说主要有俩种判断方式。
1) 引用计数法
当有对象引用自身时,就会计数器加1,删除一个引用时就会减1,当计数为0时即可判断为垃圾。引用计数存在循环引用问题,俩个落单的A/B相互引用,但是没有其他对象指向他们。
2) 可达性分析
通过一些根节点开始,分析引用链,没有被引用的对象都可以被标记为垃圾对象。根节点是方法栈中的引用,常量等。
1.5
垃圾收集算法
1.5.1
标记清除
对非垃圾对象进行标记,清除其他的对象。这种方式对内存空间造成空隙,即内存碎片。最终导致有空余空间,但没有连续的足够大的空间来分配内存。
1.5.2
标记整理
标记非垃圾对象后,将这些对象整理好,排列到内存的开始位置,这样内存就是整齐的了。但是因为会造成对象移动,所以效率比较低。
1.5.3
标记清除整理
上述俩种方式的结合,在若干次清楚后进行一次整理。
1.5.4
复制
划分俩个大小相同的区域,收集时,将第一个区域的活对象复制到另外一个区域,这样就不会有碎片问题,但是最多只能存放一半的内存,内存使用效率低。
1.6
垃圾收集器
垃圾收集器是垃圾算法的具有实现。
1.6.1
Serial New
新生代单线程的收集器,是Client模式默认的垃圾收集器。(JVM分为server和Client俩种模式,server模式在启动时,比Client模式慢10%,但是一旦运行起来之后,性能将会有很大提升;java –version可以查看)
1.6.2
Parallel New
Serial New的多线程版本。常和CMS搭配使用。
Parallel和concurrent即并行和并发,在垃圾收集这里的表示不同,并行表示有多个线程同时进行垃圾回收,并发是指垃圾收集线程和应用线程可以并发执行。
1.6.3
Parallel Scanvenge
PS收集器是注重吞吐来那个的收集器
1.6.4
Serial Old
老年代的单线程收集器
1.6.5
Parallel Old
Serial Old的多线程版本。
1.6.6
CMS(concurrent
mark sweep)
注重延迟latency的收集器,在交互式应用中,如果面向用户的WEB应用,需要尽可能较少垃圾收集造成的停顿时间,在总的统计上,吞吐量可能没有PS收集器高。
CMS的四个阶段:
a. 初始标记,标记GC
Root可以直达的对象(STW:在执行垃圾收集算法时,java应用程序的i其他所有除了垃圾回收帮助器线程之外的线程都将会被挂起)
b. 并发标记,从第一部标记的对象开始,进行可达性分析遍历,和应用线程并发执行
c. 重新标记,修正上一阶段并发执行造成的引用变化(STW)
d. 并发清除,并发的清除垃圾。
CMS使用的是标记清除算法,所以有内存碎片的问题,可以设置参数在进行若干次不带整理的收集之后,进行一次带整理的收集。另外,因为垃圾收集是和应用线程并发执行的,在收集的同时可能还会有垃圾产生,即产生了垃圾浮动现象。另外还需要预留出一定空间,到达这个值后进行收集,但是还会有收集速度赶不上产生的速度,这时就会出现concurrent mode failure,CMS会退化成serial
Old 进行GC。
1.6.7
G1收集器
Java 7中的垃圾收集器。具有大内存收集和目标效率时间控制的能力,目标是代替CMS。G1通过将内存划分成不同的区域(region),并对不同的区域计算分数,分析哪个区域最具有回收价值。
1.7
Minor GC、major GC和Full GC
1.7.1
Minor GC
从年轻代空间(包括 Eden 和 Survivor 区域)回收内存被称为 Minor GC。这一定义既清晰又易于理解。但是,当发生Minor GC事件的时候,有一些有趣的地方需要注意到:
1)当 JVM 无法为一个新的对象分配空间时会触发 Minor GC,比如当 Eden 区满了。所以分配率越高,越频繁执行 Minor GC。
2)内存池被填满的时候,其中的内容全部会被复制,指针会从0开始跟踪空闲内存。Eden 和 Survivor 区进行了标记和复制操作,取代了经典的标记、扫描、压缩、清理操作。所以 Eden 和 Survivor 区不存在内存碎片。写指针总是停留在所使用内存池的顶部。
3)执行 Minor GC 操作时,不会影响到永久代。从永久代到年轻代的引用被当成 GC roots,从年轻代到永久代的引用在标记阶段被直接忽略掉。
4)质疑常规的认知,所有的 Minor GC 都会触发“全世界的暂停(stop-the-world)”,停止应用程序的线程。对于大部分应用程序,停顿导致的延迟都是可以忽略不计的。其中的真相就 是,大部分 Eden 区中的对象都能被认为是垃圾,永远也不会被复制到 Survivor 区或者老年代空间。如果正好相反,Eden 区大部分新生对象不符合 GC 条件,Minor GC 执行时暂停的时间将会长很多。
所以
Minor GC 的情况就相当清楚了——每次 Minor GC 会清理年轻代的内存。
1.7.2
Major GC和Full GC
Major GC 是清理老年代。
Full GC 是清理整个堆空间—包括年轻代和老年代。
Java体系结构---垃圾回收的更多相关文章
- JAVA的垃圾回收机制
1. 垃圾回收的意义 在C++中,对象所占的内存在程序结束运行之前一直被占用,在明确释放之前不能分配给其它对象:而在Java中,当没有对象引用指向原先分配给某个对象的内存时,该内存便成为垃圾.JVM的 ...
- 全面分析Java的垃圾回收机制
Java的堆是一个运行时数据区,类的实例(对象)从中分配空间.Java虚拟机(JVM)的堆中储存着正在运行的应用程序所建立的所有对象,这些对象通过new.newarray.anewarray和mult ...
- 记录Java的垃圾回收机制和几种引用
一.Java的垃圾回收机制 Java的垃圾回收机制(java garbage collection)是Java虚拟机提供的能力,用于在空闲时间以不定时的方式动态回收无任何引用的对象占据的堆内存空间. ...
- 关于为什么java需要垃圾回收
为什么java采用垃圾回收而c++却不采用,这是因为在java中,所有对象变量都是引用,当一个引用被新对象覆盖掉时,就没有引用指向原来的对象了,这个对象就“失控了”. 而C++中,除非使用特殊符号&a ...
- Java 的垃圾回收机制(转)
先看一段转载,原文出自 http://jefferent.iteye.com/blog/1123677 虚拟机中的共划分为三个代:年轻代(Young Generation).年老点(Old Gener ...
- 面试题-Java基础-垃圾回收
1.Java中垃圾回收有什么目的?什么时候进行垃圾回收? 垃圾回收的目的是识别并且丢弃应用不再使用的对象来释放和重用资源. 2.System.gc()和Runtime.gc()会做什么事情? 这两个方 ...
- Java的垃圾回收
Java的垃圾回收 System.gc()和Runtime.gc()用来请求JVM启动垃圾回收 try与return的问题 任何调用try 或者catch中的return语句之前,都会先执行final ...
- Java虚拟机垃圾回收(三) 7种垃圾收集器
Java虚拟机垃圾回收(三) 7种垃圾收集器 主要特点 应用场景 设置参数 基本运行原理 在<Java虚拟机垃圾回收(一) 基础>中了解到如何判断对象是存活还是已经死亡?在<Java ...
- Java虚拟机垃圾回收:内存分配与回收策略 方法区垃圾回收 以及 JVM垃圾回收的调优方法
在<Java对象在Java虚拟机中的创建过程>了解到对象创建的内存分配,在<Java内存区域 JVM运行时数据区>中了解到各数据区有些什么特点.以及相关参数的调整,在<J ...
随机推荐
- Windows与Linux文件系统互访的几种方法
首先,我们知道基于文件的几种服务:ftp,sftp,这两种服务都是文件传输服务,偏重于网络传输,并不是实时互访.通常,我们需要在远程和本地 同时操作同一个目录,如:在Windows下使用各种强大的ID ...
- C#与Java互通AES算法加密解密
/// <summary>AES加密</summary> /// <param name="text">明文</param> /// ...
- Div里面载入另一个页面的实现(取代框架)(AJax)
随着框架越来越不火了,HTML5就不对框架支持了,iframe也只有url了,Div就担当了此大任 DIV+CSS在页面部局确实也很让人满意,使用也更方便 今天突然遇到一个问题,那就是需要导入另一个页 ...
- JavaSwing JScrollPane的使用
JavaSwing JScrollPane的使用: 参考:http://duyz.blog.ifeng.com/article/340649.html package com.srie.test; i ...
- HTML 颜色名
目前所有浏览器都支持以下颜色名. 141个颜色名称是在HTML和CSS颜色规范定义的(17标准颜色,再加124).下表列出了所有颜色的值,包括十六进制值. 提示: 17标准颜色:黑色,蓝色,水,紫红 ...
- puppet的配置清单书写
puppet的配置清单书写 1使用数组,合并同类的 例如你想安装很多软件,如果分开来写的话,很麻烦,不简洁,这时我们可以使用数组来完成 以前我们这样来写 class packages{ package ...
- GDB中的backtrace命令
backtrace命令,可以用于回溯函数调用栈. 例如:当出现段错误的时候,执行backtrace,可以看到是哪里的调用,产生的这个段错误.
- <C++Primer>第四版 阅读笔记 第一部分 “基本语言”
之前阅读时没有及时总结,现在慢慢补上. 第1章 快速入门 main 函数在很多方面都比较特别,其中最重要的是每个C++程序必须含有 main 函数,且 main 函数是(唯一)被操作系统显示调用的函数 ...
- php 引入文件 include 和require
php 如何引用文件? 先建一个php 文件,php文件名要和所建的类名相同, 然后直接在php 中用include("")/include"" 和requir ...
- 2.SQL语言进阶
0.实验数据 表1.course表 表2.student表 表3.sc表 1.SQL连接 内连接 select * from student,sc where student.sno=sc.sno;/ ...