java内存区域与内存溢出异常

一、运行时数据区域

  

  1.程序计数器:线程私有,用于存储当前所执行的指令位置

  2.Java虚拟机栈:线程私有,描叙Java方法执行模型;执行方法时都会创建一个栈帧,存储局部变量,基本类型变量,引用等信息

  3.Java本地方法栈:线程私有,为虚拟机使用到的Native方法服务

  4.Java堆:线程共享,是垃圾收集器的主要工作地方;存储对象实例等

  5.方法区:线程共享;存储类信息,常量,静态变量等

    运行时常量:存放编译时生成的各种字面量和符号引用

  6.直接内存:机器的内存

二、虚拟机对象

  1.对象的创建

  • 先检查常量池能否定位到此类的符号引用,并检查类是否已经加载初始化,否则要先执行加载过程;
  • 为对象分配内存:计算空间并从堆中划分一块连续或不连续的区域;使用的是cas+失败重试,避免线程安全问题(因为对象创建十分频繁,不知道当前内存有没有被分配出去)
  • 初始化内存空间:将分配的内存空间初始化0值
  • 设置对象基本信息:元数据、hash码、gc等
  • 执行java的init初始化:

  2.对象的内存布局

    对象头:存储对象的hash码、锁状态等 和 类型指针(对象所指向类的元数据)

    实例数据:对象真正存储的信息

    对齐填充:填充符合规则

  3.对象的访问定位

    对象的访问,通过java栈上的reference数据,它维护了一个指向对象的引用

    访问方式:句柄和直接访问

      

      句柄:堆中维护句柄池,reference指向句柄,句柄中包含了对象实例数据和类型数据的地址信息

        移动方便,直接修改句柄中的实例数据即可;开销大,多了一次指针定位

     

      直接:reference直接指向对象地址

        速度快

三、实战OutofMemoryERROR

  1.java堆溢出

    参数:-Xms堆最小值;-Xmx堆最大值;-XX:+HeapDumpOnOutOfMemoryError出现溢出时内存快照分析

    堆中存放的是对象:可以创建大量对象来实现堆溢出:heap space

  2.栈溢出

    参数:-Xss设置栈值

    栈深度,可以通过无限递归增加栈深度、或创建大量线程实现

//递归来StackOverFlower
public class JavaVMStackSOF {
private int stackLength = 1;
public void stackLeak(){
stackLength++;
stackLeak();
}
public static void main(String[] args)throws Throwable{
JavaVMStackSOF oom = new JavaVMStackSOF();
try {
oom.stackLeak();
} catch(Throwable e){
System.out.println("stack length:" + oom.stackLength);
throw e;
}
}
}

  3.方法区和常量池溢出

    参数:-XX:PermSize方法区大小;-XX:MaxPermSize方法区最大大小

      在JDK1.6前,可以通过创建大量的String,虚拟机会复制对象放入常量池,从而溢出

      在1.7及以后,不可以这样,因为虚拟机只会在常量池中保存首次出现此对象时对象的引用

      方法区的溢出:方法区保存的是类的信息,通过产生大量的动态类来溢出,如spring其实也是通过动态代理产生的类

public class JavaMethodAreaOOM{
public static void main(String[]args){
while(true){//创建大量的动态类,动态代理OOMObject
Enhancer enhancer=new Enhancer();
enhancer.setSuperclass(OOMObject.class);
enhancer.setUseCache(false);
enhancer.setCallback(new MethodInterceptor(){
public Object intercept(Object obj,Method method,Object[]args,MethodProxy proxy)throws Throwable{
return proxy.invokeSuper(obj,args);
}}
);
enhancer.create();
}}
static class OOMObject{
}
}

  String.intern()是一个Native方法,它的作用是:如果字符串常量池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象;否则,将此String对象包含的字符串添加到常量池中,并且返回此String对象的引用

  JDK6及以前:方法区(永久代)是单独的,常量池在方法区内

  JDK7:去永久代

public class RuntimeConstantPoolOOM{
public static void main(String[]args){
String str1=new StringBuilder("计算机").append("软件").toString();
System.out.println(str1.intern()==str1);
String str2=new StringBuilder("ja").append("va").toString();
System.out.println(str2.intern()==str2);
}
}

  这段代码在JDK 1.6中运行,会得到两个false,而在JDK 1.7中运行,会得到一个true和一个false。

  产生差异的原因是:在JDK 1.6中,intern()方法会把首次遇到的字符串实例复制到永久代中,返回的也是永久代中这个字符串实例的引用,而由StringBuilder创建的字符串实例在Java堆上,所以必然不是同一个引用,将返回false。

  而JDK 1.7:intern()实现不会再复制实例,只是在常量池中记录首次出现的实例引用,因此intern()返回的引用和由StringBuilder创建的那个字符串实例是同一个。

  对str2比较返回false是因为“java”这个字符串在执行StringBuilder.toString()之前已经出现过,字符串常量池中已经有它的引用了,不符合“首次出现”的原则,而“计算机软件”这个字符串则是首次出现的,因此返回true

  注意:1.7及以后保存的是首次出现的引用;理解上面的分析

  4.本机直接内存

    参数:-XX:MaxDirectMemorySize直接内存大小;默认==最大堆内存

深入了解Java虚拟机(1)java内存区域与内存溢出异常的更多相关文章

  1. 深入理解java虚拟机系列(一):java内存区域与内存溢出异常

    文章主要是阅读<深入理解java虚拟机:JVM高级特性与最佳实践>第二章:Java内存区域与内存溢出异常 的一些笔记以及概括. 好了開始.假设有什么错误或者遗漏,欢迎指出. 一.概述 先上 ...

  2. Java虚拟机-----------Java内存区域与内存溢出异常

    Java内存区域划分 Java虚拟机运行时的数据区大致可划分为五部分:方法区,堆(两部分组成Java堆内存),虚拟机栈,本地方法栈(Java栈内存),程序计数器. 1.程序计数器 程序计数器占较小的内 ...

  3. Java虚拟机之Java内存区域

    Java虚拟机运行时数据区域 ⑴背景:对于c/c++来说程序员来说,需要经常去关心内存运行情况,但对于Java程序员,只需要在必要时关心内存运行情况,这是因为在Java虚拟机自动内存管理机制的帮助下, ...

  4. 深入理解Java虚拟机之Java内存区域随笔

    1.java内存区域与内存溢出异常 Java 虚拟机在执行 Java 程序的过程中会把它管理的内存划分成若干个不同的数据区域:1.程序计数器,2.栈(虚拟机栈和本地方法栈 ),3.堆,4.方法区(包含 ...

  5. 《深入理解java虚拟机》第二章 Java内存区域与内存溢出异常

    第二章 Java内存区域与内存溢出异常 2.2 运行时数据区域  

  6. Java虚拟机--Java内存区域的划分和异常

    Java内存区域的划分和异常 运行时数据区域 JVM在运行Java程序时候会将内存划分为若干个不同的数据区域. 程序计数器 线程私有.可看作是当前线程所执行的字节码的行号指示器,字节码解释器的工作是通 ...

  7. 深入理解java虚拟机-第二章:java内存区域与内存泄露异常

    2.1概述: java将内存的管理(主要是回收工作),交由jvm管理,确实很省事,但是一点jvm因内存出现问题,排查起来将会很困难,为了能够成为独当一面的大牛呢,自然要了解vm是怎么去使用内存的. 2 ...

  8. 深入理解Java虚拟机(1)--Java内存区域

    运行时数据区域 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域有各自的用途,以及创建和销毁的时间,有的区域随着虚拟机进程的启动而存在,有些区域则是依赖用 ...

  9. 深入理解java虚拟机---->java内存区域与内存溢出异常

    2. java内存区域于内存溢出异常 2.1 概述: 对于C/C++而言,内存管理具有最高的权利,既拥有每一个对象的“所有权”,又担负着每一个对象生命开始到结束的维护责任. 对于java而言,则把内存 ...

随机推荐

  1. TFS应用层服务器获取F5用户的真实IP地址(高可用性)

    当用户数量达到一定级别(例如2千)以上,为保证TFS系统的持续服务,最大程度减少因系统宕机对研发团队的影响,系统管理员一般会考虑应用层和数据库层的高可用性方案. 在应用层的高可用性方案中,目前比较常见 ...

  2. linux系统编程之文件与IO(三):利用lseek()创建空洞文件

    一.lseek()系统调用 功能说明: 通过指定相对于开始位置.当前位置或末尾位置的字节数来重定位 curp,这取决于 lseek() 函数中指定的位置 函数原型: #include <sys/ ...

  3. 设计模式之代理模式(Proxy Pattern)_远程代理解析

    一.什么是代理模式? 顾名思义,代理就是第三方,比如明星的经纪人,明星的事务都交给经纪人来处理,明星只要告诉经纪人去做什么,经纪人自然会想办法去做,做完之后再把结果告诉明星就好了 本来是调用者与被调用 ...

  4. 【C#进阶】委托那些事儿(一)

    一.简单的委托 1.1 委托的声明: C#当中,委托(delegate)是一种方法封装,也即委托对象可以作为一种传递方法的变量来使用. 委托也算是一种类,与类是平级的存在.在类中写delegate对象 ...

  5. PowerDesigner 生成C#实体模版代码

    操作步骤见:  https://blog.csdn.net/da454122373/article/details/54346217 最后的template 模版代码如下: .if (%isValid ...

  6. 使用FFMpeg命令行录屏推rtmp流

    最近在做局域网内屏幕分享方面的东西,要把录制一台设备的屏幕然后实时推送给内网的一个或多个用户. 做了很多实验,效果还没有达到要求,这里分享一下推rtmp流的实验. 实验使用到的各种工具:FFmpeg. ...

  7. 3.jquery在js文件中获取选择器对象

    一.常用的选择器有一下几种: 1.标签选择器 2.类选择器 3.id选择器 4.并集选择器 5.层级选择器 二.如何获取选择器对象: <!DOCTYPE html> <html la ...

  8. jzoj100044

    完全背包問題 我們可以將數組內每個元素看成一個物品,這樣問題就轉化成: 現有n個物品,每個物品可以取a[i]~b[i]個,價值為d[i],費用為c[i],問怎麼樣取讓費用為0且價值最大 我們可以先每種 ...

  9. [Python]Threading.Thread之Daemon线程

    之前对Daemon线程理解有偏差,特记录说明: 一.什么是Daemon A thread can be flagged as a "daemon thread". The sign ...

  10. Chrome谷歌浏览器已停用不支持的扩展程序解决方法

    在不能上外网的情况下解决该问题: http://www.liu16.com/post/Chrome_2447.html