HotSpot 自动内存管理笔记与实战
1.对象的创建
虚拟机遇到一条new指令时,首先会去检查这个指令的参数是否能在常量池中定位到一个类的符号引用,并且检查这个符号引用代表的类是否已被加载、解析和初始化过。如果没有,则必须先进行相应的类的加载。
2、对象的访问定位
简历对象是为了使用对象,我们的java程序需要通过栈上的refrerence数据来操作堆上的具体对象。由于reference类型在java虚拟机规范中只规定了一个指向对象的引用,并没有定义这个引用应该通过何种方式去定位、访问堆中的对象的具体位置,所以对象访问方式也是取决于虚拟机实现而定的。目前主流的访问方式有使用句柄和直接指针两种。
使用句柄:那么 java堆中会划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息。

使用直接指针:那么Java堆对象的布局中就必须考虑如何放置访问类型数据的相关信息,而reference中存储的直接就是对象地址。

使用句柄来访问的最大好处就是refernce中存储的是稳定的句柄地址,在对象被移动时,将会改变句柄中的实例数据指针,而reference本身不需要修改。
使用直接指针访问方式的最大好处就是速度更快,它节省了一次指针定位的时间开销,由于对象的访问在JAVA中非常频繁,因此这类开销积少成多后也是一项非常可观的执行成本。
3、JAVA堆溢出
JAVA堆用于存储对象实例,不断地创建对象,并保证GC, Root到对象之间有可达路径来避免垃圾回收机制清除这些对象,那么在对象数量到达最大堆的容量限制后就会产生内存溢出异常。
下面设置运行参数为 -Xms521M -Xmx512M -XX:+HeapDumpOnOutOfMemoryError,让虚拟机出现内存溢出异常时Dump出当前的内存堆转储快照以便事后进行分析。

package JVMtest; import java.util.ArrayList;
import java.util.List; public class HeapOOM {
static class OOMObject{ } public static void main(String[] args){
List<OOMObject> list = new ArrayList<OOMObject>();
while(true){
list.add(new OOMObject());
}
}
}

将堆的最小值-Xms参数与最大值-Xmx参数设置为一样即可避免堆自动扩展
4、虚拟机栈和本地方法栈溢出
栈容量只由-Xss参数设定。关于虚拟机栈和本地方法栈,在JAVA虚拟机规范中描述了两种异常:
(1)如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常。
(2)如果虚拟机在扩展栈时无法申请到足够的内存空间,则抛出OutOfMemoryError异常。
测试时,通过不断地创建线程的方式倒是可以产生内存溢出异常,但这样产生的内存溢出异常与栈空间是否足够大并不存在任何联系,或者再准确的说,在这种情况下,为每个线程的栈分配的内存越大,反而越容易产生内存溢出的异常。原因是,操作系统分配给每个进程的内存是有限制的,譬如32为的Windows限制为2GB,虚拟机提供了参数来控制JAVA堆和方法去的两部分最大的内存值。那么剩下的内存为,操作系统限制的2GB-Xms(最大堆容量)-MaxPermSize(最大方法区容量),程序计数器消耗内存很小,可以忽略。如果虚拟机本身消耗的内存不计算在内,剩下的内存就由虚拟机和本地方法栈瓜分了。每个线程分配到的栈容量越大,可以建立的线程数量自然就减少,建立线程时,就很容易把剩下的内存耗尽。
package JVMtest;
public class JavaVMStackOOM {
private void dontStop(){
while(true){
}
}
public void stackLeankByThread(){
while(true){
Thread thread = new Thread(new Runnable(){
@Override
public void run() {
dontStop();
}
});
thread.start();
}
}
public static void main(String args[]){
JavaVMStackOOM oom = new JavaVMStackOOM();
oom.stackLeankByThread();
}
}

5、方法区和运行时异常量池溢出
比如String.intern()是一个Native方法,作用是,如果字符串常量池中已经包含一个等于此String对象的字符串,则返回带包翅中这个字符串的String对象;否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用。
方法区用于存放Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。这些区域的测试,基恩的思路是运行时产生大量的类去填满方法区,直到溢出。
package JVMtest; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy; public class JavaMethodAreaOOM {
public static void main(String args[]){
while(true){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(OOMObject.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor(){ @Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
return proxy.invokeSuper(obj,args);
} });
enhancer.create();
}
}
static class OOMObject{ }
}
HotSpot 自动内存管理笔记与实战的更多相关文章
- JVM自动内存管理学习笔记
对于使用 C.C++ 的程序员来说,在内存管理领域,他们既是拥有最高权力的皇帝又是从事最基础工作的劳动人民——拥有每一个对象的“所有权”,又担负着每一个对象生命开始到终结的维护责任.对于 Java 程 ...
- [深入理解Java虚拟机]<自动内存管理>
Overview 走近Java:介绍Java发展史 第二部分:自动内存管理机制 程序员把内存控制的权利交给了Java虚拟机,从而可以在编码时享受自动内存管理.但另一方面一旦出现内存泄漏和溢出等问题,就 ...
- JVM自动内存管理机制--读这篇就GO了
之前看过JVM的相关知识,当时没有留下任何学习成果物,有些遗憾.这次重新复习了下,并通过博客来做下笔记(只能记录一部分,因为写博客真的很花时间),也给其他同行一些知识分享. Java自动内存管理机制包 ...
- 深入理解Java虚拟机(自动内存管理机制)
文章首发于公众号:BaronTalk 书籍真的是常读常新,古人说「书读百遍其义自见」还是很有道理的.周志明老师的这本<深入理解 Java 虚拟机>我细读了不下三遍,每一次阅读都有新的收获, ...
- JVM | 第1部分:自动内存管理与性能调优《深入理解 Java 虚拟机》
目录 前言 1. 自动内存管理 1.1 JVM运行时数据区 1.2 Java 内存结构 1.3 HotSpot 虚拟机创建对象 1.4 HotSpot 虚拟机的对象内存布局 1.5 访问对象 2. 垃 ...
- JVM自动内存管理-Java内存区域与内存溢出异常
摘要: JVM内存的划分,导致内存溢出异常的可能区域. 1. JVM运行时内存区域 JVM在执行Java程序的过程中会把它所管理的内存划分为以下几个区域: 1.1 程序计数器 程序计数器是一块较小的内 ...
- JVM介绍&自动内存管理机制
1.介绍JVM(Java Virtual Machine,Java虚拟机) JVM是Java Virtual Machine的缩写,通常成为java虚拟机,作为Java可以进行一次编写,到处执行(Wr ...
- JVM自动内存管理机制——Java内存区域(下)
一.虚拟机参数配置 在上一篇<Java自动内存管理机制——Java内存区域(上)>中介绍了有关的基础知识,这一篇主要是通过一些示例来了解有关虚拟机参数的配置. 1.Java堆参数设置 a) ...
- JVM自动内存管理机制——Java内存区域(上)
一.JVM运行时数据区域概述 Java相比较于C/C++的一个特点就是,在虚拟机自动内存管理机制的帮助下,我们不需要为每一个操作都写像C/C++一样的delete/free代码,所以也不容易出现内存泄 ...
随机推荐
- dynamic_cast 和 static_cast 隐式类型转换的区别
首先回顾一下C++类型转换: C++类型转换分为:隐式类型转换和显式类型转换 第1部分. 隐式类型转换 又称为“标准转换”,包括以下几种情况:1) 算术转换(Arithmetic conversion ...
- 第一章Android系统移植与驱动开发概述--读书笔记
以前,初步学习过嵌入式Linux驱动开发的基础课程,对于驱动开发可以说是有了一点点微末的基础吧.首先我们要对Android嵌入式系统有一个初步的认识,Android系统发展到今天已经具备了完善的架构. ...
- 隐藏UITableView多余的分割线
先看看没有隐藏是什么效果以及代码是什么情况,这样更加直观
- tinyxml一个优秀的C++ XML解析器
读取和设置xml配置文件是最常用的操作,试用了几个C++的XML解析器,个人感觉TinyXML是使用起来最舒服的,因为它的API接口和Java的十分类似,面向对象性很好. TinyXML是一个开源的解 ...
- 分布式系统(Distributed System)资料
这个资料关于分布式系统资料,作者写的太好了.拿过来以备用 网址:https://github.com/ty4z2008/Qix/blob/master/ds.md 希望转载的朋友,你可以不用联系我.但 ...
- WPF学习笔记——依赖属性(Dependency Property)
1.什么是依赖属性 依赖属性是一种可以自己没有值,并且通过Binding从数据源获得值(依赖在别人身上)的属性,拥有依赖属性的对象被称为"依赖对象". 依赖项属性通过调用 Regi ...
- tabelView右滑选择进行删除
如何使用UITableViewRowAction实现右滑选择呢? 1.在iOS8以前,我们实现tableview中滑动显示删除,置顶,更多等等的按钮时,都需要自己去实现,在iOS8中系统已经写好了,只 ...
- github:如何获取项目源代码
github是流行的源码管理平台.这上面有很多开源的项目.作为普通的用户,如何获取这些开源项目的源码呢? 1.首先需要注册一个github账号. 2.安装windows下的git工具:下载地址: ht ...
- Dos学习笔记(1)dir命令
这个命令是最常用的命令,就像linux的ls一样,同样他也有很多很多optionnal field供我们选择, 看了半天,觉得自己离盲打肯定还是有很大的差距的,现在只是想体验一下dos,或者说感受下这 ...
- php面试题及答案
1.用PHP打印出前一天的时间,格式是2006-5-10 22:21:21 <?php //echo date('Y-m-d H:i:s',time()-60*60*24 echo da ...