在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. tiny4412--linux驱动学习(2)

    在ubuntu下编写验证字符设备驱动 1,准备工作 uname -r  查看电脑版本信息 apt-get  install  linux-source  安装相应版本的linux内核 2,编写驱动程序 ...

  2. localhost换成127.0.0.1和本机IP打不开本地项目了的问题

    点击桌面右下角的小三角, iis express右键—>显示所有应用程序—>点击网站名称,配置文件路径,找到配置文件,以记事本打开, 按照configuration--system.app ...

  3. Oracle 12c 创建新的数据库实例、用户

    前提:安装好了Oracle 12c数据库,已有一个数据库实例xe,登录用户/密码:system/oralce 我用的是docker安装的Oracle 12c的实例: docker run --name ...

  4. 如何打开用eclipse没有.project文件的Java工程

    大概分为以下7个步骤,具体如下: 1.在你的eclipse下新建一个与你想要打开的源代码项目同名的一个项目(我这举例叫myweb). 2.在电脑磁盘中找到刚刚新建的项目,把它生成的.project文件 ...

  5. PHP中写定时任务

    1.写一个bat E:\Progra~1\wamp\php\php.exe -f "E:\service.php" 2.写接口文件 ignore_user_abort(); //即 ...

  6. SystemUI中设置横竖屏显示

    SystemUI中快捷菜单有 “方向锁定” . RotationLockTile protected void handleClick() { if (mController == null) ret ...

  7. Vue源码解析---数据的双向绑定

    本文主要抽离Vue源码中数据双向绑定的核心代码,解析Vue是如何实现数据的双向绑定 核心思想是ES5的Object.defineProperty()和发布-订阅模式 整体结构 改造Vue实例中的dat ...

  8. Appium+Python自动化 2 定位元素方式

    1.找到 Android SDK安装路径tools 下面的 uiautomatorviewer.bat,如下截图 2.点击uiautomatorviewer.bat进行启动,左上角一共四个按钮,作用分 ...

  9. 201771010142 张燕& 杨蓉庆 实验十一 集合

    实验十一   集合 实验时间 2018-11-8 一  理论知识 一般将数据结构分为两大类:线性数据结构和非线性数据结构.线性数据结构:线性表.栈.队列.串.数组和文件.非线性数据结构:树和图. 线性 ...

  10. xbee3的先进性功能用法

    xbee3以及xbee3 PRO 是digi无线模块的又一大突破:不仅实现了所有2.4G的模块整合,更在以后的程序更新中会增加蓝牙功能:它打通了xbee系列1和系列2之间的壁垒:不同于xbee S2C ...