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 自动内存管理笔记与实战的更多相关文章

  1. JVM自动内存管理学习笔记

    对于使用 C.C++ 的程序员来说,在内存管理领域,他们既是拥有最高权力的皇帝又是从事最基础工作的劳动人民——拥有每一个对象的“所有权”,又担负着每一个对象生命开始到终结的维护责任.对于 Java 程 ...

  2. [深入理解Java虚拟机]<自动内存管理>

    Overview 走近Java:介绍Java发展史 第二部分:自动内存管理机制 程序员把内存控制的权利交给了Java虚拟机,从而可以在编码时享受自动内存管理.但另一方面一旦出现内存泄漏和溢出等问题,就 ...

  3. JVM自动内存管理机制--读这篇就GO了

    之前看过JVM的相关知识,当时没有留下任何学习成果物,有些遗憾.这次重新复习了下,并通过博客来做下笔记(只能记录一部分,因为写博客真的很花时间),也给其他同行一些知识分享. Java自动内存管理机制包 ...

  4. 深入理解Java虚拟机(自动内存管理机制)

    文章首发于公众号:BaronTalk 书籍真的是常读常新,古人说「书读百遍其义自见」还是很有道理的.周志明老师的这本<深入理解 Java 虚拟机>我细读了不下三遍,每一次阅读都有新的收获, ...

  5. JVM | 第1部分:自动内存管理与性能调优《深入理解 Java 虚拟机》

    目录 前言 1. 自动内存管理 1.1 JVM运行时数据区 1.2 Java 内存结构 1.3 HotSpot 虚拟机创建对象 1.4 HotSpot 虚拟机的对象内存布局 1.5 访问对象 2. 垃 ...

  6. JVM自动内存管理-Java内存区域与内存溢出异常

    摘要: JVM内存的划分,导致内存溢出异常的可能区域. 1. JVM运行时内存区域 JVM在执行Java程序的过程中会把它所管理的内存划分为以下几个区域: 1.1 程序计数器 程序计数器是一块较小的内 ...

  7. JVM介绍&自动内存管理机制

    1.介绍JVM(Java Virtual Machine,Java虚拟机) JVM是Java Virtual Machine的缩写,通常成为java虚拟机,作为Java可以进行一次编写,到处执行(Wr ...

  8. JVM自动内存管理机制——Java内存区域(下)

    一.虚拟机参数配置 在上一篇<Java自动内存管理机制——Java内存区域(上)>中介绍了有关的基础知识,这一篇主要是通过一些示例来了解有关虚拟机参数的配置. 1.Java堆参数设置 a) ...

  9. JVM自动内存管理机制——Java内存区域(上)

    一.JVM运行时数据区域概述 Java相比较于C/C++的一个特点就是,在虚拟机自动内存管理机制的帮助下,我们不需要为每一个操作都写像C/C++一样的delete/free代码,所以也不容易出现内存泄 ...

随机推荐

  1. SQL 事务

    /*========================事务==============================*/begin tran--开始事务 --开始写流程语句 --语句写完之后if @@ ...

  2. 你必须牢记的*.Config-配置文件

    在我们第一次写web应用程序的时候,我们很快会接触到一个文件,那就是配置文件——web.config.我们的第一个比较深刻 的使用就是我们不需要把我们的数据库链接零散的写在我们的代码中了,我们只需要在 ...

  3. [转]: 两分钟彻底让你明白Android Activity生命周期(图文)!

    转自:http://blog.csdn.net/android_tutor/article/details/5772285 大家好,今天给大家详解一下Android中Activity的生命周期,我在前 ...

  4. js 常见弹出框学习

    模拟系统的弹出框 系统自带的弹出框 总结 链接  http://blog.csdn.net/anhuidelinger/article/details/17024491 参考这个网站学习模态框的动态弹 ...

  5. 2-Spark高级数据分析-第二章 用Scala和Spark进行数据分析

    数据清洗时数据科学项目的第一步,往往也是最重要的一步. 本章主要做数据统计(总数.最大值.最小值.平均值.标准偏差)和判断记录匹配程度. Spark编程模型 编写Spark程序通常包括一系列相关步骤: ...

  6. iOS AppStore提交错误收集

    ERROR ITMS-90535: "Unexpected CFBundleExecutable Key. The bundle at 'Payload/创可贴.app/TencentOpe ...

  7. 用bugzilla统计BUG

    bugzilla—— reports—— Tabular reports—— 选择版本号啥的跟search一样 上面的行标Vertical Axis选Resolution:列标Horizontal A ...

  8. Eclipse中的Link with Editor功能是如何实现

    Eclipse中的Link with Editor功能是如何实现 - kaukiyou的专栏 - 博客频道 - CSDN.NEThttp://blog.csdn.net/kaukiyou/articl ...

  9. (转)LINUX测试环境部署Redis(四)

    安装配置Redis 第一部分:安装redis  希望将redis安装到此目录 1 /usr/local/redis 希望将安装包下载到此目录 1 /usr/local/src 那么安装过程指令如下: ...

  10. DB2 claim与drain

    DB2使用claim & drain来控制SQL与utility对数据库对象的访问. claim说明有对象正在访问或是将要访问该对象,而drain则是在对象上面加一个drain lock,等所 ...