在Java虚拟机规范的描述中,除了程序计数器外,虚拟机内存的其他几个运行时区域都有发生 OutOfMemoryError 异常的可能。

在Eclipse中进行JVM参数设置

可以直接通过上方菜单栏的 Run 下的 Run Configurations... 或者 Debug Configurations... 选项进行设置。

双击 Java Application 会生成一个新的配置卡。

在新的配置卡中可配置名称Name,Main里面的Project配置项目名,Main class配置main方法所在的类。

(如果是从main方法里面右键打开的Run As-->Run Configurations...或者Debug As-->Debug Configurations...,这几项会自己生成)

Arguments下面的VM arguments 里面配置虚拟机参数。

参数解释:

1,堆是存储对象实例的,创建的对象都是在堆中进行内存分配的;设置堆的大小:-Xmx20M(最大值) ,-Xms20M(最小值),其中-Xmn设置年轻代大小。

2,栈是存储局部变量,操作栈,动态链接,方法出口(都在栈桢中) 的地方,调用方法时,会创建栈桢;设置栈的大小:-Xss128K。

3,方法区是存放Class的相关信息,如类名,访问修饰符,常量池,字段描述,方法描述等。此外运行时常量池是属于方法区的,即存放常量,静态常量等;设置方法区大小,-XX:PermSize=10M和-XX:MaxPermSize=10M。

4,本地直接内存;设置本地直接内存大小:-XX:MaxDirectMemorySize(默认与-Xmx的值一样)。

堆内存溢出

Java堆用于存储对象实例,只要不断的创建对象,并且保证 GC Roots 到对象之间有可达路径来避免垃圾回收机制清除这些对象,那么在对象数量到达最大堆的容量限制后就会产生内存溢出异常。

参数设置:-verbose:gc -Xms20M -Xmx20M -XX:+HeapDumpOnOutOfMemoryError

限制Java堆的大小为20M,不可扩展(将堆的最小值 -Xms 参数和最大值 -Xmx 参数设置一样即可避免堆自动扩展),通过参数 -XX:+HeapDumpOnOutOfMemoryError 可以让虚拟机在出现内存溢出异常时 Dump 出当前的内存堆转储快照以便事后进行分析。

代码:

package jvm;

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<>(); while (true) {
list.add(new OOMObject());
} } }

运行结果:

栈内存溢出

在HotSpot虚拟机中并不区分虚拟机栈和本地方法栈,所以 -Xoss 参数无效,栈容量只由 -Xss 参数控制。

参数设置:-Xss128k

代码:

package jvm;

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;
} } }

运行结果:

方法区内存溢出

参数设置:-XX:PermSize=10M -XX:MaxPermSize=10M

注意:JDK8中用 MetaspaceSize 代替 PermSize,因此将 -XX:PermSize=10M -XX:MaxPermSize=10M 修改为 -XX:MetaspaceSize=10M -XX:MaxMetaspaceSize=10M

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

代码一:

package jvm;

import java.util.ArrayList;
import java.util.List; public class RuntimeConstantPoolOOM { public static void main(String[] args) {
// 使用List保持常量池引用,避免 Full GC 回收常量池行为
List<String> list = new ArrayList<>();
// 10MB的 PermSize在Integer范围内足够产生OOM了
int i = 0;
while (true) {
list.add(String.valueOf(i++).intern());
} } }

以上代码在JDK1.6及之前的版本下,由于常量池分配在永久带内,运行时常量池溢出,使用JDK1.7以及更高版本运行这段程序不会得到相同结果,while循环将一直进行下去。因为1.7及更高版本的常量池值只保存了引用。

代码二:

package jvm;

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); } }

运行结果:

结果分析:

JDK1.6会得到两个false。

在JDK1.6中,intern() 方法会把首次遇到的字符串实例复制到永久代中,返回的也是永久带中这个字符串实例的引用。而 StringBuilder 创建的字符串实例在堆上,所以不是同一个引用,返回 false。

JDK1.7中会得到一个true和一个false。

在JDK1.7中,intern() 方法不会再复制实例,只在常量池中记录首次出现的实例引用,该引用指向的是堆中的实例,这个实例就是 StringBuilder 创建的那个字符串实例,所以是同一个引用,返回true。

返回false是因为 “java” 这个字符串在中StringBuilder之前已经出现过,字符串常量池中已经有它的引用了,而 StringBuilder 又重新创建了一个“java”字符串实例,所以str2中保存的是新创建的实例的引用,而str2.intern() 返回的是旧的实例的引用,所以不是同一个引用,返回false。

代码三:

package jvm;

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 {
} }

以上代码使用使用CGLib使方法区出现内存溢出异常。使用到下面的两个jar包。

JDK8运行结果:

本机直接内存溢出

参数设置:-Xmx20M  -XX:MaxDirectMemorySize=10M

直接内存容量可通过 MaxDirectMemorySize 指定,如果不指定,则默认和Java堆最大值一样(-Xmx)。

代码:

package jvm;

import java.lang.reflect.Field;

import sun.misc.Unsafe;

public class DirectMemoryOOM {

    private static final int _1MB = 1024 * 1024;

    public static void main(String[] args) throws Exception {
//通过反射获取实例
Field unsafeField = Unsafe.class.getDeclaredFields()[0];
unsafeField.setAccessible(true);
Unsafe unsafe = (Unsafe) unsafeField.get(null);
while (true) {
//申请分配内存
unsafe.allocateMemory(_1MB);
}
} }

运行结果:

Java 虚拟机的内存溢出的更多相关文章

  1. 深入理解java虚拟机【内存溢出实例】

    通过简单的小例子程序,演示java虚拟机各部分内存溢出情况: (1).java堆溢出: Java堆用于存储实例对象,只要不断创建对象,并且保证GC Roots到对象之间有引用的可达,避免垃圾收集器回收 ...

  2. 如何写出让java虚拟机发生内存溢出异常OutOfMemoryError的代码

    程序小白在写代码的过程中,经常会不经意间写出发生内存溢出异常的代码.很多时候这类异常如何产生的都傻傻弄不清楚,如果能故意写出让jvm发生内存溢出的代码,有时候看来也并非一件容易的事.最近通过学习< ...

  3. java虚拟机涉及内存溢出

    Java语言写的代码是.java文件,它会被特定程序编译(javac.exe,它会被Eclipse之类的IDE调用)成字节码(bytecode),字节码不能直接在CPU上运行,需要另一个程序读取并执行 ...

  4. java虚拟机(四)--内存溢出、内存泄漏、SOF

    学习了java运行时数据区,知道每个内存区域保存什么数据,可以参考:https://www.cnblogs.com/huigelaile/p/diamondshine.html,然后了 解内存溢出和内 ...

  5. 【java虚拟机】内存溢出与内存泄漏

    作者:平凡希 原文地址:https://www.cnblogs.com/xiaoxi/p/7354857.html 一.基本概念 内存溢出:简单地说内存溢出就是指程序运行过程中申请的内存大于系统能够提 ...

  6. 【java虚拟机】内存溢出解决思路

    转自:https://blog.csdn.net/u013521220/article/details/79523633 内存溢出与数据库锁表的问题,可以说是开发人员的噩梦,一般的程序异常,总是可以知 ...

  7. (一)深入java虚拟机之内存溢出与分析

    一.内存溢出程序 public class Test { public static void main(String[] args) { List<User> userList=new ...

  8. 实战Java虚拟机之一“堆溢出处理”

    从今天开始,我会发5个关于java虚拟机的小系列: 实战Java虚拟机之一“堆溢出处理” 实战Java虚拟机之二“虚拟机的工作模式” 实战Java虚拟机之三“G1的新生代GC” 实战Java虚拟机之四 ...

  9. 从Java虚拟机的内存区域、垃圾收集器及内存分配原则谈Java的内存回收机制

    一.引言: 在Java中我们只需要轻轻地new一下,就可以为实例化一个类,并分配对应的内存空间,而后似乎我们也可以不用去管它,Java自带垃圾回收器,到了对象死亡的时候垃圾回收器就会将死亡对象的内存回 ...

随机推荐

  1. java常用集合浅层解析-面试必备

    ArrayList 1.动态数组 2.线程不安全 3.存储空间连续 4.查询快,添加删除慢 构造方法 /** + Shared empty array instance used for defaul ...

  2. hid.dll

    hid.dll是USB的HID相关动态链接库文件,缺少它可能会造成usb设备无法正常使用.当你的电脑弹出提示“计算机缺少hid.dll”或“无法找到hid.dll Hkapi.dll HKComman ...

  3. OO第一单元三次作业总结

    写在前面 第一单元作业是针对输入的多项式进行格式合法判断,然后进行求导,结果长度优化,最后输出.三次难度递增,不断添加新的需求,总体感觉在实现方面没有多大困难(?),个人主要困扰环节是寻找自己未知bu ...

  4. openTSDB (rpm)安装 + Grafana 视图

    1.提前安装环境 操作系统:CentOS OpenTSDB版本:2.0.1 JDK版本:1.8.1_101 Apache HBase版本:1.1.2 2.安装Grafana yum安装grafana ...

  5. 【竞价网站绝技】根据访客ip,页面显示访客所属城市的html代码(借用YY IP地址库)

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  6. 《Linux就该这么学》第十二天课程

    使用ssh服务管理远程主机 绑定两块网卡 原创地址:https://www.linuxprobe.com/chapter-09.html 第1步:在虚拟机系统中再添加一块网卡设备,请确保两块网卡都处在 ...

  7. 中标麒麟(linux)下Qt调用python数据转换

    转自:https://blog.csdn.net/itas109/article/details/78733478 mytest.py文件 # -*- coding: utf-8 -*- def he ...

  8. TCP的三次握手 与 四次挥手

    TCP的连接建立是一个三次握手过程,目的是为了通信双方确认开始序号,以便后续通信的有序进行 主要步骤: 服务器一定处于Listen状态,否则客户端发过来的连接会被拒绝.注:服务器和客户端的角色是相对的 ...

  9. Cortext-A7_i.MX 6ULL——多模式DDR控制器(MMDC)

    1.概述 i.MX 6ULL系列芯片的MMDC是一个多模式DDR控制器,支持DDR3/DDR3Lx16和LPDDR2x16的存储类型,MMDC是可配置,高性能,优化的内存控制器. 注:DDR3/DDR ...

  10. Unity3D协程yield的理解

    Unity3D的协程概括地将就是:对于一段程序,你可以加上yield标明哪里需要暂停,然后在下一帧或者一段时间后,系统会继续执行这段代码.协程的作用:①延迟一段时间执行代码.②等某个操作完成之后再执行 ...