JVM内存分配及GC简述
在阐述JVM的内存区域之前,先来看下计算机的存储单位。从小到大依次为Bit,Byte,KB,MB,GB,TB。相邻的单位相差2的10次方。
计算机运行中的存储元件主要分为寄存器(位于CPU)和内存,寄存器和内存之间通过地址总线连接。地址总线的宽度影响了物理地址的索引范围,因为总线宽度决定了处理器一次可以从寄存器或内存中获取多少个Bit,同时也决定了处理器最大可以寻址的地址空间。
这些地址空间被划分为了内核空间和用户空间,程序只能使用用户空间的内存。内核空间主要是指操作系统运行时所使用的用于程序调度、虚拟内存的使用或者链接硬件资源的程序逻辑。区分内核空间和用户空间的目的主要是从系统的稳定性的角度考虑的。Windows 32操作系统默认内核空间和用户空间的比例是1:1,即2G内核空间、2G内存空间,32位Linux系统中默认比例则是1:3,即1G内核空间,3G内存空间。
字长CPU的主要技术指标之一,指的是CPU一次能并行处理二进制的位数(Bit)。通常称处理字长为8位数据的CPU为8位CPU,32位CPU就是在同一时间内处理字长为32位的二进制数据。不过目前虽然CPU大多是64位的,但还是以32位字长运行。
JVM(Java Virtual Machine,Java虚拟机)定义了程序在运行时需要使用到的内存区域,大致分为5个部分:
1.Method Area(Non-Heap)(方法区) ——线程共享
2.Heap(堆) ——线程共享
3.Program Counter Register(程序计数器) ——非线程共享
4.VM Stack(虚拟机栈)——非线程共享
5.Native Method Stack ( 本地方法栈 )——非线程共享
JVM运行的时候会分配好Method Area(方法区)和Heap(堆);JVM 每遇到一个线程,就为其分配一个Program Counter Register(程序计数器), VM Stack(虚拟机栈)和Native Method Stack (本地方法栈), 当线程终止时,三者(虚拟机栈,本地方法栈和程序计数器)所占用的内存空间也会被释放掉。
非线程共享的那三个区域的生命周期与所属线程相同,而线程共享的区域与Java程序运行生命周期相同,这也是GC只发生在线程共享的区域(大部分发生在Heap上)的原因。
另外,JVM在运行时为数据分配区域,还会对不适用的数据予以垃圾回收(GC),从而确保程序运行中对内存的正常需求。那么,JVM在进行垃圾回收时,哪些内存会被回收呢?主要是针对不再被任何场景使用的对象。JVM在进行垃圾回收时主要在堆区以及方法区内进行,其中尤以回收堆区中不适用的对象为多。
一.线程共享的内存区域
1.Method Area(方法区)
(1)《Java虚拟机规范》只是规定了有方法区这么个概念和它的作用,但是并没有规定如何去实现它。一般来说,在Java8以前,方法区通过永久代(PermGen)实现;从Java8开始,Java废弃了永久代(方法区的实现),并替换为Metaspace(元空间,位于本地内存中)。方法区内很少发生垃圾回收,在这里进行的GC主要是方法区里的常量池和类型的卸载。
元空间是方法区在HotSpot jvm 中的实现,方法区主要用于存储类的信息、常量池、方法数据、方法代码等。方法区逻辑上属于堆的一部分,但是为了与堆进行区分,通常又叫“非堆”。
元空间的本质和永久代类似,都是对JVM规范中方法区的实现。不过元空间与永久代之间最大的区别在于:元空间并不在虚拟机中,而是使用本地内存,它在理论上取决于32位/64位系统可虚拟的内存大小。
(2)方法区主要用来存储已被虚拟机加载的类信息、常量、静态变量和即时编译后的代码等数据。
(3)方法区里有一个运行时常量池(Runtime Constant Pool),用于存放静态编译产生的字面量和符号引用。运行时生成的常量也会存在这个常量池中。比如String类的intern()方法。
GC在方法区内主要回收废弃常量和无用的类。废弃常量是指没有再被符号引用的常量;无用的类要同时满足三个条件:该类所有的实例都被回收;加载该类的ClassLoader已被回收;该类对应的java.lang.Class对象未在任何地方被引用,无法在任何地方通过反射访问该类。
2.Heap(堆)
堆空间在虚拟机启动时创建,几乎所有的对象实例都在这里创建,因此该区域经常发生垃圾回收操作。
堆空间分为新生代(有时也称为“年轻代”)和老年代。刚创建的对象存放在新生代,而老年代中存放生命周期长久的实例对象。新生代中又被分为Eden区(圣经中的伊甸园)和两个Survivor区(From Space和To Space)。新的对象分配是首先放在Eden区,Survivor区作为Eden区和Old区的缓冲,在Survivor区的对象经历若干次收集仍然存活的,就会被转移到老年代。一般来说,位于老年代的对象不易被回收,这是因为该区域内的对象存活率极高。
在JDK1.2之前,Java中引用的定义很传统:如果引用类型的数据中存储的数值代表的是另一块内存的起始地址,就称这块内存代表着一个引用。这种定义很纯粹,也过于狭隘,一个对象只有被引用或者没被引用两种状态。
在JDK1.2之后,Java对引用的概念进行了扩充,将引用分为强引用、软引用、弱引用、虚引用4种,这4种引用强度依次减弱。
①强引用
代码中普遍存在的类似"Object obj = new Object()"这类的引用,只要强引用还存在,GC 垃圾收集器永远不会回收掉被引用的对象。
②软引用
描述有些还有用但并非必需的对象。在系统将要发生内存溢出异常之前,将会把这些对象列进回收范围进行二次回收。如果这次回收还没有足够的内存,才会抛出内存溢出异常。Java中的类SoftReference表示软引用。
③弱引用
描述非必需对象。被弱引用关联的对象只能生存到下一次垃圾回收之前,垃圾收集器工作之后,无论当前内存是否足够,都会回收掉只被弱引用关联的对象。Java中的类WeakReference表示弱引用。
④虚引用
这个引用存在的唯一目的就是在这个对象被收集器回收时收到一个系统通知,被虚引用关联的对象,和其生存时间完全没关系。Java中的类PhantomReference表示虚引用。
GC(Garbage Collection,垃圾收集)在堆中进行垃圾回收时,当一个对象大于eden区而小于old区(老年代)时,GC会将其直接扔到old区。当对象大于old区时,会直接抛出OutOfMemoryError(OOM)。
一般来说,GC回收的是已经没有引用的对象,那怎么判断一个对象没有引用?这里需要简单介绍2种方法:引用计数法和可达性分析算法;
这里简单说一下引用计数法:对象中添加一个引用计数器,每当有一个地方引用,计数器就增加1,引用失效就减少1,计数器为0就不可用;缺点在于无法处理对象直接相互引用的问题,因为相互引用以后无法使计数器为0,所以无法回收。
可达性分析算法,也就是我们常说的GC Root,,当一个对象没有与任何引用链相连的时候,就可以对该对象进行回收,下面是Java中GC Root对象使用的几个地方:
有三种场景会触发GC:第一种是当年轻代或者老年代满了,Java虚拟机无法再为新的对象分配内存空间了,那么Java虚拟机就会触发一次GC去回收掉那些已经不会再被使用到的对象;第二种是手动调用System.gc()方法,通常这样会触发一次Full GC以及至少一次的Minor GC;第三种是程序运行的时候有一条低优先级的GC线程,它是一条守护线程,当这条线程处于运行状态的时候,自然就触发了一次GC。
(1)新生代GC(Minor GC)
指发生在新生代的垃圾收集动作,因为大多数Java对象存活率都不高,所以Minor GC非常频繁,一般回收速度也比较快。
(2)老年代GC(Major GC/Full GC)
指发生在老年代的垃圾收集动作,出现了Major GC,经常会伴随至少一次的Minor GC(但并不是绝对的)。Major GC的速度一般要比Minor GC慢上10倍以上。
二.线程私有的内存区域
1.VM Stack(虚拟机栈)
虚拟机栈也就是我们平常所称的栈内存,它为java方法服务,每个方法在执行的时候都会创建一个栈帧,用于存储局部变量表、操作数栈、动态链接和方法出口等信息。
栈帧是一个内存区块,是一个数据集,是一个有关方法(Method)和运行期数据的数据集,当一个方法 A 被调用时就产生了一个栈帧 F1,并被压入到栈中,A 方法又调用了 B 方法,于是产生栈帧 F2 也被压入栈,执行完毕后,先弹出 F2栈帧,再弹出 F1 栈帧,遵循“先进后出”原则。
栈帧保存了创建栈帧的方法的返回地址和局部变量。每个栈帧都包含一个指向运行时常量池中该栈帧所属方法的引用,持有这个引用是为了支持方法调用过程中的动态连接。动态链接就是将常量池中的符号引用在运行期转化为直接引用。
栈内存的生命期是跟随线程的生命周期的,线程结束栈内存也就释放,对于栈来说不存在垃圾回收问题,只要线程一结束,该栈就 Over,所以不存在垃圾回收。
局部变量表存放了编译期可知的各种基本数据类型(boolean、byte、char、short、int、float、long、double)、对象的引用(reference类型,不等同于对象本身,根据不同的虚拟机实现,可能是一个指向对象起始地址的引用指针,也可能是一个代表对象的句柄或者其他与对象相关的位置)和 returnAdress类型(指向下一条字节码指令的地址)。局部变量表所需的内存空间在编译期间完成分配,在方法运行之前,该局部变量表所需要的内存空间是固定的,运行期间也不会改变。
2.Native Method Stack(本地方法栈)
本地方法栈和虚拟机栈类似,只不过本地方法栈为Native方法服务。
3.Program Counter Register(程序计数器)
代表着当前线程所执行字节码的行号指示器。分支、循环、跳转、异常处理和线程恢复等功能都需要依赖这个计数器完成。程序计数器是唯一一个java虚拟机规范没有规定任何OOM(Out Of Memory)情况的区域。
JVM内存分配及GC简述的更多相关文章
- JVM内存分配及GC流程
-verbose 这是查询GC问题最常用的命令之一,具体参数如: -verbose:class 输出jvm载入类的相关信息,当jvm报告说找不到类或者类冲突时可此进行诊断. -verbose:gc 输 ...
- JVM初探- 内存分配、GC原理与垃圾收集器
JVM初探- 内存分配.GC原理与垃圾收集器 标签 : JVM JVM内存的分配与回收大致可分为如下4个步骤: 何时分配 -> 怎样分配 -> 何时回收 -> 怎样回收. 除了在概念 ...
- 最简单例子图解JVM内存分配和回收
一.简介 JVM采用分代垃圾回收.在JVM的内存空间中把堆空间分为年老代和年轻代.将大量(据说是90%以上)创建了没多久就会消亡的对象存储在年轻代,而年老代中存放生命周期长久的实例对象.年轻代中又被分 ...
- 管中窥豹——从对象的生命周期梳理JVM内存结构、GC调优、类加载、AOP编程及性能监控
如题,本文的宗旨既是透过对象的生命周期,来梳理JVM内存结构及GC相关知识,并辅以AOP及双亲委派机制原理,学习不仅仅是海绵式的吸收学习,还需要自己去分析why,加深对技术的理解和认知,祝大家早日走上 ...
- JVM 内存分配模型概念和java中各种对象的存储
JVM 内存分配模型概念 --在工作中可能用到的机会不多,有个概念的了解 --此文是转载某位读者,应该是在阅读了<深入理解Java虚拟机JVM高级特性与最佳实践> 一书后,总结所得.写的不 ...
- 最简单例子图解JVM内存分配和回收(转)
本文转自http://ifeve.com/a-simple-example-demo-jvm-allocation-and-gc/ http://www.idouba.net/a-simple-exa ...
- 一个可以参考的JVM内存分配
下面是java命令有关JVM内存分配的参数 JAVA_MEM_OPTS="" BITS=`java -version >& | -bit` if [ -n " ...
- JVM内存管理及GC机制
一.概述 Java GC(Garbage Collection,垃圾收集,垃圾回收)机制,是Java与C++/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代码,对内存泄露 ...
- 第二章 JVM内存分配
注意:本篇博客,主要参考自以下四本书 <分布式Java应用:基础与实践> <深入理解Java虚拟机(第二版)> <突破程序员基本功的16课> <实战java虚 ...
随机推荐
- Connections between cities HDU - 2874(最短路树 lca )
题意: 给出n个点m条边的图,c次询问 求询问中两个点间的最短距离. 解析: Floyd会T,所以用到了最短路树..具体思想为: 设k为u和v的最近公共祖先 d[i] 为祖结点到i的最短距离 则di ...
- OEM SLP Key
OEM SLP Key Windows Server 2012 R2 Datacenter ===================== 2N9T6-Y284D-T68G9-QGV6X-FRFTD -- ...
- 【BZOJ5319】军训列队(主席树)
[BZOJ5319]军训列队(主席树) 题面 BZOJ 洛谷 题解 一眼题既视感... 首先很明显,每次询问的结果显然是做一次离散. 然后直接上主席树就好了... 查询答案的方式也很简单 考虑一下那个 ...
- HDU.2612 Find a way (BFS)
HDU.2612 Find a way (BFS) 题意分析 圣诞节要到了,坤神和瑞瑞这对基佬想一起去召唤师大峡谷开开车.百度地图一下,发现周围的召唤师大峡谷还不少,这对基佬纠结着,该去哪一个...坤 ...
- position:fixed 相对父元素定位
position:fixed是对于浏览器窗口定位的,要实现相当于父元素定位,可以这样: 不设置fixed元素的top,bottom,left,right,只设置margin来实现. 这种方法本质上fi ...
- 高性能相关、Scrapy框架
高性能相关 在编写爬虫时,性能的消耗主要在IO请求中,当单进程单线程模式下请求URL时必然会引起等待,从而使得请求整体变慢. import requests def fetch_async(url): ...
- C#调用GDI+1.1中的函数实现高斯模糊、USM锐化等经典效果。
http://www.cnblogs.com/Imageshop/archive/2012/12/13/2815712.html 在GDI+1.1的版本中,MS加入不少新的特性,其中的特效类Effec ...
- SVN Server 500 NotLicensed 错误的解决方法
SVN Server 500 NotLicensed 错误的HTML页面显示 Not licensed The server encountered an internal error or misc ...
- Codeforces Round #404 (Div. 2)A B C二分
A. Anton and Polyhedrons time limit per test 2 seconds memory limit per test 256 megabytes input sta ...
- nginx如何配置虚拟主机
server { listen 80; #listen [::]:80 default_server ipv6only=on; server_name local.presion.caomall.ne ...