JVM——内存管理和垃圾回收
1. 何为GC
转载请注明出处:http://blog.csdn.net/seu_calvin/article/details/51892567
Java与C语言相比的一个优势是,可以通过自己的JVM自动分配和回收内存空间。
垃圾回收机制是由垃圾收集器Garbage Collection来实现的,GC是后台一个低优先级的守护进程。在内存中低到一定限度时才会自动运行,因此垃圾回收的时间是不确定的。
为何要这样设计:因为GC也要消耗CPU等资源,如果GC执行过于频繁会对Java的程序的执行产生较大的影响,因此实行不定期的GC。
与GC有关的是:JVM运行时数据区中的堆(对象实例会存储在这里)和 gabagecollector方法。
垃圾回收GC只能回收通过new关键字申请的内存(在堆上),但是堆上的内存并不完全是通过new申请分配的。还有一些本地方法,这些内存如果不手动释放,就会导致内存泄露,所以需要在finalize中用本地方法(nativemethod)如free操作等,再使用gc方法。
System.gc();
2. 何为垃圾
Java中那些不可达的对象就会变成垃圾。对象之间的引用可以抽象成树形结构,通过树根(GC Roots)作为起点,从这些树根往下搜索,搜索走过的链称为引用链。
当一个对象到GC Roots没有任何引用链相连时,则证明这个对象是不可用的,该对象会被判定为可回收的对象。
可以作为GC Roots的主要有以下几种:
(1)虚拟机栈(栈帧中的本地变量表)中引用的对象。
(2)方法区中类静态属性引用的对象。
(3)方法区中常量引用的对象
(4)本地方法栈中JNI(即一般说的Native方法)引用的对象。
//垃圾产生的情况举例:
//1.改变对象的引用,如置为null或者指向其他对象
Object obj1 = new Object();
Object obj2 = new Object();
obj1 = obj2; //obj1成为垃圾
obj1 = obj2 = null ; //obj2成为垃圾
//2.引用类型
//第2句在内存不足的情况下会将String对象判定为可回收对象,第3句无论什么情况下String对象都会被判定为可回收对象
String str = new String("hello");
SoftReference<String> sr = new SoftReference<String>(new String("java"));
WeakReference<String> wr = new WeakReference<String>(new String("world"));
//3.循环每执行完一次,生成的Object对象都会成为可回收的对象
for(int i=0;i<10;i++) {
Object obj = new Object();
System.out.println(obj.getClass());
}
//4.类嵌套
class A{
A a;
}
A x = new A();//分配了一个空间
x.a = new A();//又分配了一个空间
x = null;//产生两个垃圾
//5.线程中的垃圾
calss A implements Runnable{
void run(){
//....
}
} //main
A x = new A();
x.start();
x=null; //线程执行完成后x对象才被认定为垃圾
3. 四种引用类型
3.1 强引用
Object obj = newObject();
这里的obj引用便是一个强引用,强引用不会被GC回收。当内存空间不足,Java虚拟机宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足问题。
3.2 软引用
如果一个对象只具有软引用,那就类似于可有可无的生活用品。如果内存空间足够,垃圾回收器就不会回收它,如果内存空间不足了,就会回收这些对象的内存。
软引用可用来实现内存敏感的高速缓存。
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。
3.3 弱引用
如果一个对象只具有弱引用,那就类似于可有可无的生活用品。
弱引用与软引用的区别在于:只具有弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。
3.4 虚引用
虚引用主要用来跟踪对象被垃圾回收器回收的活动。
虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。
当垃圾回收器一个对象有虚引用时,就会把这个虚引用对象加入到与之关联的引用队列中。此时该对象并没有被GC回收。而是要等到ReferenceQueue被真正的处理后才会被回收。
程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。
由于Object.finalize()方法的不安全性、低效性,常常使用虚引用完成对象回收前的资源释放工作。
这里特别需要注意:当JVM将虚引用插入到引用队列的时候,虚引用执行的对象内存还是存在的。但是PhantomReference并没有暴露API返回对象。所以如果我想做清理工作,需要继承PhantomReference类,以便访问它指向的对象。如NIO直接内存的自动回收,就使用到了sun.misc.Cleaner。
4. 典型的垃圾回收算法
在确定了哪些垃圾可以被回收后,垃圾收集器要做的事情就是开始进行垃圾回收,但是这里面涉及到一个问题是:如何高效地进行垃圾回收。下面讨论几种常见的垃圾收集算法。
4.1 Mark-Sweep(标记-清除)算法
标记-清除算法分为两个阶段:标记阶段和清除阶段。
标记阶段的任务是标记出所有需要被回收的对象,清除阶段就是回收被标记的对象所占用的空间。
标记-清除算法实现起来比较容易,但是有一个比较严重的问题就是容易产生内存碎片,碎片太多可能会导致后续过程中需要为大对象分配空间时无法找到足够的空间而提前触发GC。
4.2 Copying(复制)算法
为了解决Mark-Sweep算法的缺陷,Copying算法就被提了出来。它将可用内存按容量划分为大小相等的两块,每次只使用其中的一块。当这一块的内存用完了,就将还存活着的对象复制到另外一块上面,然后再把第一块内存上的空间一次清理掉,这样一来就不容易出现内存碎片的问题,并且运行高效。
但是该算法导致能够使用的内存缩减到原来的一半。而且,该算法的效率跟存活对象的数目多少有很大的关系,如果存活对象很多,那么Copying算法的效率将会大大降低。(这也是为什么后面提到的新生代采用Copying算法)
4.2 Mark-Compact(标记-整理)算法
为了解决Copying算法的缺陷,充分利用内存空间,提出了Mark-Compact算法。
该算法标记阶段和Mark-Sweep一样,但是在完成标记之后,它不是直接清理可回收对象,而是将存活的对象都移向一端,然后清理掉端边界以外的所有内存(只留下存放存活对象的一端,留下存活对象)。
4.4 Generational Collection(分代收集)算法
分代收集算法是目前大部分JVM的垃圾收集器采用的算法。
它的核心思想是将堆区划分为老年代(Tenured Generation)和新生代(Young Generation),老年代的特点是每次垃圾收集时只有少量对象需要被回收,而新生代的特点是每次垃圾回收时都有大量的对象需要被回收,那么就可以在不同代的采取不同的最适合的收集算法。
目前大部分垃圾收集器对于新生代都采取Copying算法,因为新生代中每次垃圾回收都要回收大部分对象,也就是说需要复制的操作次数较少,该算法效率在新生代也较高。但是实际中并不是按照1:1的比例来划分新生代的空间的,一般来说是将新生代划分为一块较大的Eden空间(任何新进入运行时数据区的实例都放在Eden)和两块较小的Survivor空间(称之为A空间和B空间),每次使用Eden空间和其中的一块Survivor空间(A空间),当进行回收时,将Eden和Survivor中还存活的对象复制到另一块Survivor空间(B空间)中,然后清理掉Eden和A空间。B空间如果无法有足够空间存储某个对象(大对象),就会将该对象移动到老年代中。在进行了第一次GC之后,使用的便是Eden space和B空间了,下次GC时会将存活对象复制到A空间,如此反复循环。
当对象在Survivor区躲过一次GC的话,其对象年龄便会加1,默认情况下,对象年龄达到15时,就会移动到老年代中。一般来说,大对象会被直接分配到老年代,所谓的大对象是指需要大量连续存储空间的对象,最常见的一种大对象就是大数组,比如:byte[] data = newbyte[4*1024*1024]。
当然分配的规则并不是百分之百固定的,这要取决于当前使用的是哪种垃圾收集器组合和JVM的相关参数。这些搬运工作都是GC完成的,GC不仅负责在Heap中搬运实例,同时负责回收存储空间。
最后,因为每次回收都只回收少量对象,所以老年代一般使用的是Mark-Compact算法。
注意,在方法区中有一个永久代(Permanet Generation),它用来存储class类、常量、方法描述等。对永久代的回收主要回收两部分内容:废弃常量和无用的类。
有关查看垃圾回收信息的JVM常见配置方式:
-XX:+PrintGCDetails
最后介绍一下有关堆的JVM常见配置方式:
-Xss //选置栈内存的大小
-Xms: //初始堆大小
-Xmx: //最大堆大小
-XX:NewSize=n: //设置年轻代大小
-XX:NewRatio=n: //设置年轻代和年老代的比值。比如设置为3,表示年轻代与年老代比值为1:3
-XX:SurvivorRatio=n: //年轻代中Eden区与两个Survivor区的比值。注意Survivor区有两个。比如设置为3,表示Eden:Survivor=3:2,一个Survivor区占整个年轻代的1/5。
-XX:MaxPermSize=n: //设置持久代大小
5. 典型的垃圾回收器
垃圾收集算法是内存回收的理论基础,而垃圾收集器就是内存回收的具体实现。
下面介绍一下HotSpot(JDK 7)虚拟机提供的几种垃圾收集器,用户可以根据自己的需求组合出各个年代使用的收集器。
1.Serial/Serial Old
Serial/Serial Old收集器是最基本最古老的收集器,它是一个单线程收集器,并且在它进行垃圾收集时,必须暂停所有用户线程。Serial收集器是针对新生代的收集器,采用的是Copying算法,Serial Old收集器是针对老年代的收集器,采用的是Mark-Compact算法。它的优点是实现简单高效,但是缺点是会给用户带来停顿。
2.ParNew
ParNew收集器是Serial收集器的多线程版本,使用多个线程进行垃圾收集。
3.Parallel Scavenge
Parallel Scavenge收集器是一个新生代的多线程收集器(并行收集器),它在回收期间不需要暂停其他用户线程,其采用的是Copying算法,该收集器与前两个收集器有所不同,它主要是为了达到一个可控的吞吐量。
4.Parallel Old
Parallel Old是Parallel Scavenge收集器的老年代版本(并行收集器),使用多线程和Mark-Compact算法。
5.CMS
CMS(Current Mark Sweep)收集器是一种以获取最短回收停顿时间为目标的收集器,它是一种并发收集器,采用的是Mark-Sweep算法。
6.G1
G1收集器是当今收集器技术发展最前沿的成果,它是一款面向服务端应用的收集器,它能充分利用多CPU、多核环境。因此它是一款并行与并发收集器,并且它能建立可预测的停顿时间模型。
最后介绍一下有关收集器设置的JVM常见配置方式:
-XX:+UseSerialGC: //设置串行收集器
-XX:+UseParallelGC: //设置并行收集器
-XX:+UseParalledlOldGC: //设置并行年老代收集器
-XX:+UseConcMarkSweepGC: //设置并发收集器
//并行收集器设置
-XX:ParallelGCThreads=n: //设置并行收集器收集时使用的CPU数,并行收集线程数
-XX:MaxGCPauseMillis=n: //设置并行收集最大暂停时间
-XX:GCTimeRatio=n: //设置垃圾回收时间占程序运行时间的百分比,公式为1/(1+n)
//并发收集器设置
-XX:+CMSIncrementalMode: //设置为增量模式。适用于单CPU情况
-XX:ParallelGCThreads=n: //设置并发收集器年轻代收集方式为并行收集时,使用的CPU数。并行收集线程数
JVM——内存管理和垃圾回收的更多相关文章
- Java之美[从菜鸟到高手演变]之JVM内存管理及垃圾回收
很多Java面试的时候,都会问到有关Java垃圾回收的问题,提到垃圾回收肯定要涉及到JVM内存管理机制,Java语言的执行效率一直被C.C++程序员所嘲笑,其实,事实就是这样,Java在执行效率方面确 ...
- JVM内存管理及垃圾回收【转】
很多Java面试的时候,都会问到有关Java垃圾回收的问题,提到垃圾回收肯定要涉及到JVM内存管理机制,Java语言的执行效率一直被C.C++程序员所嘲笑,其实,事实就是这样,Java在执行效率方面确 ...
- JVM原理(Java代码编译和执行的整个过程+JVM内存管理及垃圾回收机制)
转载注明出处: http://blog.csdn.net/cutesource/article/details/5904501 JVM工作原理和特点主要是指操作系统装入JVM是通过jdk中Java.e ...
- JVM内存管理和垃圾回收机制介绍
http://backend.blog.163.com/blog/static/20229412620128233285220/ 内存管理和垃圾回收机制是JVM最核心的两个组成部分,对其内部实 ...
- JVM内存管理及垃圾回收
一.JVM内存的构 Java虚拟机会将内存分为几个不同的管理区,这些区域各自有各自的用途,根据不同的特点,承担不同的任务以及在垃圾回收时运用不同的算法.总体分为下面几个部分: 程序计数器(Progra ...
- JVM内存管理及垃圾回收机制
一.JVM内存组成结构 JVM栈由堆.栈.本地方法栈.方法区等部分组成,结构图如下所示: 二.JVM内存回收 Sun的JVMGenerationalCollecting(垃圾回收)原理是这样的:把对 ...
- JVM内存管理和垃圾回收
无论对于Java程序员还是大数据研发人员,JVM是必须掌握的技能之一.既是面试中经常问的问题,也是在实际业务中对程序进行调优.排查类似于内存溢出.栈溢出.内存泄漏等问题的关键.笔者将按下图分多篇文章详 ...
- (转)JVM——内存管理和垃圾回收
背景:对JVM的垃圾回收算法进行系统的总结. 转载:http://blog.csdn.net/SEU_Calvin/article/details/51892567 1. 何为GC Java与C语言 ...
- JVM内存管理 + GC垃圾回收机制
2.JVM内存管理 JVM将内存划分为6个部分:PC寄存器(也叫程序计数器).虚拟机栈.堆.方法区.运行时常量池.本地方法栈 PC寄存器(程序计数器):用于记录当前线程运行时的位置,每一个线程都有一个 ...
随机推荐
- 洛谷 P3327 [SDOI2015]约数个数和 || Number Challenge Codeforces - 235E
https://www.luogu.org/problemnew/show/P3327 不会做. 去搜题解...为什么题解都用了一个奇怪的公式?太奇怪了啊... 公式是这样的: $d(xy)=\sum ...
- [转]Android TCP长连接 心跳机制及实现
背景知识 智能手机上的长连接心跳和在Internet上的长连接心跳有什么不同 Android系统的推送和iOS的推送有什么区别 几种推送的实现方式 协议 1XMPP简介 2 MQTT简介 3移动端消息 ...
- ARM 环境下使用azure powershell 从远程blob中拉去vhd 并创建虚拟机
最近需要从指定公共访问的blob中复制vhd到自己的订阅存储账户,并使用vhd创建AZURE ARM虚拟机(非经典版),而且在portal.azure.cn中无法实现虚拟机映像创建等功能,于是自己使用 ...
- AI学习一:环境安装
对于Python开发用户来讲,PIP安装软件包是家常便饭.但国外的源下载速度实在太慢,浪费时间.而且经常出现下载后安装出错问题.所以把PIP安装源替换成国内镜像,可以大幅提升下载速度,还可以提高安装成 ...
- Java编译时根据调用该方法的类或对象所属的类决定
class Base{ int x = 1; static int y = 2; } class Subclass extends Base{ int x = 4; i ...
- 洛谷 P1030 求先序排列
题目描述 给出一棵二叉树的中序与后序排列.求出它的先序排列.(约定树结点用不同的大写字母表示,长度<=8). 输入输出格式 输入格式: 2行,均为大写字母组成的字符串,表示一棵二叉树的中序与后序 ...
- http响应头状态描述
状态代码有三位数字组成,第一个数字定义了响应的类别,且有五种可能取值:1xx:指示信息--表示请求已接收,继续处理2xx:成功--表示请求已被成功接收.理解.接受3xx:重定向--要完成请求必须进行更 ...
- Chrome开发者工具关于网络请求的一个隐藏技能
这个隐藏技能的背景是,最近出于学习目的,我写了一个百度贴吧的网络爬虫,专门爬取一些指定主题的贴吧帖子. 抓取帖子用的JavaScript函数如下: function getPostByAJAX(req ...
- RSA2
进行签名的加密 package com.goboosoft.common.pay.util; import java.io.ByteArrayInputStream; import java.io.I ...
- navicat 链接数据库查看的工具 可以同时查看各种数据库 MySql SqlServer
navicat 链接数据库查看的工具 Navicat_Premium_10.0.11.0_XiaZaiBa