百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

JVM-虚拟机-参数设置及内存溢出 java虚拟机中内存划分哪些区域

nanshan 2024-12-15 15:51 10 浏览 0 评论

JVM-虚拟机-参数设置及内存溢出

之前写了一篇关于JVM专题的初步学习,这次来学习虚拟机的参数含义对性能的影响及内存溢出问题。

上一篇补充

栈上分配

虚拟机提供的一种优化技术,基本思想是,对于线程私有的对象,将它打散分配在栈上,而不分配在堆上。好处是对象跟着方法调用自行销毁,不需要进行垃圾回收,可以提高性能。

栈上分配需要的技术基础,逃逸分析。逃逸分析的目的是判断对象的作用域是否会逃逸出方法体。

任何可以在多个线程之间共享的对象,一定都属于逃逸对象。

下面是测试代码

/**
 * @Author: 非鸽传书
 * @Date: 2021/7/28 20:16
 * @Description:
 * VM 配置
 *  -server -Xmx 10m -Xms 10m -XX:+DoEscapeAnalysis -XX:+PrintGC -XX:+EliminateAllocations
 *  -XX:-UseTLAB
 *
 * -server JVM运行的模式之一, server模式才能进行逃逸分析, JVM运行的模式还有mix/client
 * -Xmx10m和-Xms10m:堆的大小
 * -XX:+DoEscapeAnalysis:启用逃逸分析(默认打开)
 * -XX:+PrintGC:打印GC日志
 * -XX:+EliminateAllocations:标量替换(默认打开): 是否允许
 * -XX:-UseTLAB 关闭本地线程分配缓冲
 * TLAB: ThreadLocalAllocBuffer, 线程本地分配缓存,事先在堆中开辟线程内存。(虚拟机在分配对象的时候也涉及到加锁,开启这个可以增加分配的效率。注意这里是在堆中所以其他线程仍然是可以访问这部分内存的)
 */
public class StackAllocatTest {

    public static class User{
        public int id = 0;
        public String name;
    }

    public static void allocUser(){
        User u = new User();
        u.id = 1;
        u.name = "非鸽传书";
    }

    public static void main(String[] args) {
        long begin = System.currentTimeMillis();

        for(int i=0; i< 1000000000; i++){
            allocUser();
        }
        long end = System.currentTimeMillis();
        System.out.println(end - begin);
    }

}

// 分别开启和关闭逃逸分析后对比程序运行时间及GC次数

栈上分配发生影响的参数就是三个,-server、-XX:+DoEscapeAnalysis和-XX:+EliminateAllocations,任何一个发生变化都不会发生栈上分配. 另外jdk1.8默认是开启栈上分配的.

对象分配

执行new指令:执行类加载过程

  • 为新生对象分配内存。为对象分配空间的任务等同于把一块确定大小的内存从Java堆中划分出来。Java堆中内存是绝对规整的,所有用过的内存都放在一边,空闲的内存放在另一边,中间放着一个指针作为分界点的指示器,那所分配内存就仅仅是把那个指针向空闲空间那边挪动一段与对象大小相等的距离,这种分配方式称为“指针碰撞”。Java堆中的内存并不是规整的,已使用的内存和空闲的内存相互交错,那就没有办法简单地进行指针碰撞了,虚拟机就必须维护一个列表,记录上哪些内存块是可用的,在分配的时候从列表中找到一块足够大的空间划分给对象实例,并更新列表上的记录,这种分配方式称为“*空闲列表*
  • 处理多线程问题方式采用CAS配上失败重试的方式保证更新操作的原子性另一种是把内存分配的动作按照线程划分在不同的空间之中进行,即每个线程在Java堆中预先分配一小块私有内存,也就是本地线程分配缓冲(Thread Local Allocation Buffer,TLAB)

对象内存布局:

对象头(Header)

  • 对象自身的运行时数据 如 hash码 锁状态 偏向锁id等等
  • 类型指针,指向对象类可以通过这个找到是属于哪个类的实例

实例数据(Instance Data): 程序代码中所定义的各种类型的字段内容

对齐填充: 虚拟机占位. 在Hotspot中要求对象大小必须是8个字节的整数倍.


参数含义及参数设置

  • 栈:

-Xss 调整大小,例如-Xss256k

  • 堆:

-Xms:堆的最小值

-Xmx:堆的最大值;

-Xmn:新生代的大小;

-XX:NewSize;新生代最小值;

-XX:MaxNewSize:新生代最大值;

  • 方法区/永久代

jdk1.7及以前:-XX:PermSize;-XX:MaxPermSize;

jdk1.8以后:-XX:MetaspaceSize; -XX:MaxMetaspaceSize

jdk1.8以后大小就只受本机总内存的限制

如:-XX:MaxMetaspaceSize=3M

  • 直接内存

-XX:MaxDirectMemorySize

其他更多的命令可百度或者谷歌查询.

Tip: -XX表示运行参数


OOM

堆溢出

虚拟机参数:-Xms5m -Xmx5m -XX:+PrintGC

代码片段1:

public class OOMHeap {
    public static void main(String[] args) {
        List<Object> list = new LinkedList<>();
        int i = 0;
        try {
            while(true){
                i++;
                if(i%10000 == 0){
                    System.out.println(i);
                }
                list.add(String.valueOf(i));
            }
        } catch (Throwable e){
            System.out.println("i:" + i + "Error:" + e);
        }
    }
}

// 输出如下
[GC (Allocation Failure)  1020K->656K(5632K), 0.0016767 secs]
[GC (Allocation Failure)  1680K->879K(5632K), 0.0011192 secs]
[GC (Allocation Failure)  1903K->1403K(5632K), 0.0084106 secs]
10000
[GC (Allocation Failure)  2427K->2443K(5632K), 0.0041601 secs]
20000
30000
[GC (Allocation Failure)  3467K->3491K(5632K), 0.0048149 secs]
[Full GC (Ergonomics)  3491K->3256K(5632K), 0.0697227 secs]
40000
[Full GC (Ergonomics)  4280K->4257K(5632K), 0.0457067 secs]
50000
[Full GC (Ergonomics)  4770K->4769K(5632K), 0.0194403 secs]
[Full GC (Ergonomics)  4770K->4770K(5632K), 0.0190617 secs]
...
i:55128Error:java.lang.OutOfMemoryError: GC overhead limit exceeded

代码片段2:

public class OOMHeap {
    public static void main(String[] args) {
        String[] strs = new String[1000000000];
    }
}

// 输出:
[GC (Allocation Failure)  1020K->664K(5632K), 0.0013220 secs]
[GC (Allocation Failure)  1688K->879K(5632K), 0.0019375 secs]
[GC (Allocation Failure)  1495K->975K(5632K), 0.0021262 secs]
[GC (Allocation Failure)  975K->999K(5632K), 0.0009794 secs]
[Full GC (Allocation Failure)  999K->914K(5632K), 0.0077754 secs]
[GC (Allocation Failure)  914K->914K(5632K), 0.0003017 secs]
[Full GC (Allocation Failure)  914K->896K(5632K), 0.0103908 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
...
  • java.lang.OutOfMemoryError: GC overhead limit exceeded 一般是(某个循环里可能性最大)在不停地分配对象,但是分配得太多,把堆撑爆了。
  • java.lang.OutOfMemoryError: Java heap space一般是分配了巨型对象

栈溢出

虚拟机参数:-Xss 256k


public class OOMStackTest {

    private int deepen = 1;

    private void recurrence(){
        deepen++;
        recurrence();
    }

    public static void main(String[] args) {
        OOMStackTest test = new OOMStackTest();
        try {
            test.recurrence();
        } catch (Throwable e){
            System.out.println("stack deep = " + test.deepen);
            e.printStackTrace();
        }
    }
}

// 输出
stack deep = 20733
java.lang.StackOverflowError
    at com.jmmq.load.jim.jvm.OOMStackTest.recurrence(OOMStackTest.java:17)
    at com.jmmq.load.jim.jvm.OOMStackTest.recurrence(OOMStackTest.java:17)
    at com.jmmq.load.jim.jvm.OOMStackTest.recurrence(OOMStackTest.java:17)
    ...
// 递归参数如果增加参数列表则栈深度会变小,因为参数也会打包到栈帧中    

java.lang.StackOverflowError 一般的方法调用是很难出现的,如果出现了要考虑是否有无限递归。

直接内存溢出

虚拟机参数 -Xmx10M -XX:MaxDirectMemorySize=10M

public class OOMDirectMemory {
    public static void main(String[] args) {
        ByteBuffer buffer = ByteBuffer.allocate(1024*1024*11);
    }
}
// 输出
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.nio.HeapByteBuffer.<init>(HeapByteBuffer.java:57)
    at java.nio.ByteBuffer.allocate(ByteBuffer.java:335)
    at com.jmmq.load.jim.jvm.OOMDirectMemory.main(OOMDirectMemory.java:12)

相关推荐

服务器温度监控--lm-sensors(服务器温度怎么看)

lm-sensors是一款linux的硬件监控的软件,可以帮助我们来监控主板,CPU的工作电压,风扇转速、温度等数据。这些数据我们通常在主板的BIOS也可以看到。当我们可以在机器运行的时候通过...

MySQL版本区别及管理(mysql版本最新版本)

MySQL版本区别及管理一.MySQL5.6与MySQL5.7安装的区别1、cmake的时候加入了bostorg2、初始化时使用mysqld--initialize替代mysql_install...

Linux技术问答系列-NO4(linux必知必会)

一.绝对路径用什么符号表示?当前目录、上层目录用什么表示?主目录用什么表示?切换目录用什么命令?绝对路径:如/etc/init.d当前目录和上层目录:./../主目录:~/切换目录:cd二...

猫盘原版系统开启ssh教程(猫盘原版系统怎么样)

猫盘是之前网上流传许久的矿渣,默认其系统不支持SSH功能,为了能打开其SSH功能,我特意制作操作教程如下:1、到网盘下载相关软件,利用猫盘系统自带功能,将assets放入个人存储目录下,并牢记对应的...

一探究竟——天融信网闸TopRules7000

网闸即:安全隔离与信息交换系统,常用作企业内外网隔离与业务互访用途。相比给服务器加多块网卡跨多个网段来说,网闸提供了更加安全的方式。探究背景:某次,网闸配置新业务,重启设备查看是否生效,结果发现刚重启...

操作系统加固通用Linux篇(linux系统加固常见操作)

1检查是否配置登陆超时时间设置编辑vi/etc/profile文件,配置TMOUT将值设置为低于300.TMOUT=3002检查是否禁止root用户登录FTP设置如下将对应配置文件中,设置roo...

zabbix agent的安装与配置(zabbix-agent安装)

Agent安装rpm-ivhzabbix-agent-3.2.4-1.el6.x86_64.rpm安装完成后,zabbixagent端已经安装完成了,zabbixagent端的配置目录位于/e...

Linux基础命令之计划任务(linux计划任务crontab)

一、计划任务1、at只能执行一次语法:at时间服务:atd必须开启123[root@xuegod163~]#/etc/init.d/atdstatus#查看服务状态atd(pid2...

Secure Delivery Center (SDC)安装指南二:Delivery Hub

免费下载SecureDeliveryCenter2015>7月23日软件分发管理神器SecureDeliveryCenter免费技术交流会,MyEclipse原厂商倾力主讲,敬请关注!...

OpenWrt 常用命令及用法!!(openwrt常用功能)

OpenWrt是一个高度可定制的嵌入式Linux操作系统,常用于路由器等网络设备。以下是一些常见的OpenWrt命令及其详细解释和示例操作:一、系统信息相关命令1.`uname-a``u...

Linux 设置定时任务crontab命令(linux定时任务cron表达式)

看了同事的脚本,发现他用了cron来自检自身的那个程序是否崩溃了,这是有多大的不自信才用这种机制的?点击(此处)折叠或打开$sudocat/var/spool/cron/crontabs/ro...

vCenter纳管ESXI主机出错(vsphere esxi)

vCenter纳管主机的大致步骤为:(1)vc和esxi交换证书,确立信任;(2)esxi把自己的资源信息同步到VC,VC建立清单。(3)VC在esxi建立几个操作用户;(4)然后下发...

从选购到安装 小白也能看懂的超全NAS经验分享

0.篇首语Hello大家好,我是KC,上一篇器材和工作流分享的文章里,有小伙伴问我怎么没有提到NAS?其实是因为前段时间碰巧更换了一台新NAS,折腾了一段时间很多内容还没来及整理和汇总,今天就...

手把手教你!如何在 Linux 服务器中搭建 Sentinel 环境?

你在Linux服务器上搭建Sentinel环境时,是不是也遇到过各种报错,要么是启动失败,要么是配置后无法正常访问控制台?看着同事顺利搭建好,自己却一头雾水,别提多着急了!其实,很多互联网大厂...

服务器被暴力破解的解决办法(二)(服务器被攻破严重吗)

上一次,我们说到小王公司服务器遭遇暴力破解,拿到解决方案回公司就开始部署。部署完成后的确起到了一定的效果,不过接下来的一个问题让他很头疼,原来黑客虽然攻入不进系统,但是依旧不依不饶的进行暴力破解。...

取消回复欢迎 发表评论: