[TOC]java
C/C++每个new操做都须要本身去delete/free,而java里面有虚拟机自动管理内存,不容易出现内存泄漏或者溢出的问题,可是不容易出现不表明不出现,了解虚拟机怎么使用和管理内存是十分重要的是,对程序优化或者问题排查有帮助。数组
运行时区域主要分为:数据结构
线程私有:多线程
Program Count Register
,线程私有,没有垃圾回收VM Stack
,线程私有,没有垃圾回收Native Method Stack
,线程私有,没有垃圾回收线程共享:函数
Method Area
,以HotSpot
为例,JDK1.8
后元空间取代方法区,有垃圾回收。Heap
,垃圾回收最重要的地方。空间很小,当前线程执行的字节码的行号指示器(线程独有,指示当前执行到哪,下一步须要执行哪个字节码),分支,循环,跳转,异常处理,线程恢复都须要依赖它。
线程私有:java
多线程实际上是线程轮流切换并分配处理器执行时间的方式实现,一个核一个具体的时间点,只会执行一个线程的指令。线程切换须要保存和恢复正确的执行位置(保护和恢复现场),因此不一样的线程须要不一样的程序计数器。性能
java
方法时,程序计数器记录的是正在执行的字节码指令地址Native
方法,程序计数器为空惟一一个没有规定任何OutOfMemory
的区域,也没有GC(垃圾回收)。学习
线程私有,生命周期和线程同样,主要是记录该线程Java方法执行的内存模型。虚拟机栈里面放着好多栈帧。注意虚拟机栈,对应是Java方法,不包括本地方法。
一个Java方法执行会建立一个栈帧,一个栈帧主要存储:优化
每个方法调用的时候,就至关于将一个栈帧放到虚拟机栈中(入栈),方法执行完成的时候,就是对应着将该栈帧从虚拟机栈中弹出(出栈)。spa
每个线程有一个本身的虚拟机栈,这样就不会混起来,若是不是线程独立的话,会形成调用混乱。线程
你们平时说的java内存分为堆和栈,其实就是为了简便的不太严谨的说法,他们说的栈通常是指虚拟机栈,或者虚拟机栈里面的局部变量表。
局部变量表通常存放着如下数据:
boolean
,byte
,char
,short
,int
,float
,long
,double
)局部变量表内存大小编译期间肯定,运行期间不会变化。空间衡量咱们叫Slot(局部变量空间)。64位的long和double会占用2个Slot,其余的数据类型占用1个Slot。
异常:
和虚拟机栈相似,对应本地方法,Native
,虚拟机规范容许语言,使用方式和数据结构不一样,有些可能将虚拟机栈和本地方法栈合并。
异常与虚拟机栈一致:
堆是内存管理最大的一块,线程共享。
虚拟机规范中说,全部的对象实例和数组都要在堆上分配。可是实际上不是全部的对象都在堆上分配,这个和JIT编译器的发展和逃逸分析技术相关。Why?
// TODO
堆的细分:新生代,老年代,再细分有Eden,From survivor,To survivor等。
堆中也有可能有线程私有的区域,分配缓冲区。
物理上能够不连续,可是逻辑上是连续的。
异常:
名为非堆,可是实际和堆同样,是线程共享的区域,主要存贮如下信息:
方法区不等于永久代,指示Hotspot虚拟机将GC分代收集拓展到方法区,也就是用永久代实现了方法区,而其余的虚拟机不必定,不是固定的。JDK1.7将永久代的字符串常量移出了。
方法区回收垃圾的效果不是很好,能够选择不回收,虚拟机能够决定,固然也可能发生内存泄漏。
异常:
运行时常量池时方法区的一部分,可是不是所有,Class
文件主要包括:
异常:
不是虚拟机运行时数据区,也不是规范规定的区域,可是使用频繁且可能会有OutOfMemoryError:内存分配异常出现。
好比,NIO(1.4)基于Channel与Buffer的I/O,能够用Native函数直接分配堆外内存,经过存储在Java堆中的DirectByteBuffer对象做为引用来操做,提升性能,不须要Java堆和Native堆都来回复制数据。
直接内存受物理的内存,或者处理器寻址空间之类的限制。
本文系JVM学习相关笔记,整理来自周志明老师的《深刻理解Java虚拟机》,无比钦佩,强烈推荐!
【做者简介】:
秦怀,公众号【秦怀杂货店】做者,技术之路不在一时,山高水长,纵使缓慢,驰而不息。这个世界但愿一切都很快,更快,可是我但愿本身能走好每一步,写好每一篇文章,期待和大家一块儿交流。
此文章仅表明本身(本菜鸟)学习积累记录,或者学习笔记,若有侵权,请联系做者核实删除。人无完人,文章也同样,文笔稚嫩,在下不才,勿喷,若是有错误之处,还望指出,感激涕零~