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

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

nanshan 2024-12-15 15:51 13 浏览 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)

相关推荐

0722-6.2.0-如何在RedHat7.2使用rpm安装CDH(无CM)

文档编写目的在前面的文档中,介绍了在有CM和无CM两种情况下使用rpm方式安装CDH5.10.0,本文档将介绍如何在无CM的情况下使用rpm方式安装CDH6.2.0,与之前安装C5进行对比。环境介绍:...

ARM64 平台基于 openEuler + iSula 环境部署 Kubernetes

为什么要在arm64平台上部署Kubernetes,而且还是鲲鹏920的架构。说来话长。。。此处省略5000字。介绍下系统信息;o架构:鲲鹏920(Kunpeng920)oOS:ope...

生产环境starrocks 3.1存算一体集群部署

集群规划FE:节点主要负责元数据管理、客户端连接管理、查询计划和查询调度。>3节点。BE:节点负责数据存储和SQL执行。>3节点。CN:无存储功能能的BE。环境准备CPU检查JDK...

在CentOS上添加swap虚拟内存并设置优先级

现如今很多云服务器都会自己配置好虚拟内存,当然也有很多没有配置虚拟内存的,虚拟内存可以让我们的低配服务器使用更多的内存,可以减少很多硬件成本,比如我们运行很多服务的时候,内存常常会满,当配置了虚拟内存...

国产深度(deepin)操作系统优化指南

1.升级内核随着deepin版本的更新,会自动升级系统内核,但是我们依旧可以通过命令行手动升级内核,以获取更好的性能和更多的硬件支持。具体操作:-添加PPAs使用以下命令添加PPAs:```...

postgresql-15.4 多节点主从(读写分离)

1、下载软件[root@TX-CN-PostgreSQL01-252software]#wgethttps://ftp.postgresql.org/pub/source/v15.4/postg...

Docker 容器 Java 服务内存与 GC 优化实施方案

一、设置Docker容器内存限制(生产环境建议)1.查看宿主机可用内存bashfree-h#示例输出(假设宿主机剩余16GB可用内存)#Mem:64G...

虚拟内存设置、解决linux内存不够问题

虚拟内存设置(解决linux内存不够情况)背景介绍  Memory指机器物理内存,读写速度低于CPU一个量级,但是高于磁盘不止一个量级。所以,程序和数据如果在内存的话,会有非常快的读写速度。但是,内存...

Elasticsearch性能调优(5):服务器配置选择

在选择elasticsearch服务器时,要尽可能地选择与当前业务量相匹配的服务器。如果服务器配置太低,则意味着需要更多的节点来满足需求,一个集群的节点太多时会增加集群管理的成本。如果服务器配置太高,...

Es如何落地

一、配置准备节点类型CPU内存硬盘网络机器数操作系统data节点16C64G2000G本地SSD所有es同一可用区3(ecs)Centos7master节点2C8G200G云SSD所有es同一可用区...

针对Linux内存管理知识学习总结

现在的服务器大部分都是运行在Linux上面的,所以,作为一个程序员有必要简单地了解一下系统是如何运行的。对于内存部分需要知道:地址映射内存管理的方式缺页异常先来看一些基本的知识,在进程看来,内存分为内...

MySQL进阶之性能优化

概述MySQL的性能优化,包括了服务器硬件优化、操作系统的优化、MySQL数据库配置优化、数据库表设计的优化、SQL语句优化等5个方面的优化。在进行优化之前,需要先掌握性能分析的思路和方法,找出问题,...

Linux Cgroups(Control Groups)原理

LinuxCgroups(ControlGroups)是内核提供的资源分配、限制和监控机制,通过层级化进程分组实现资源的精细化控制。以下从核心原理、操作示例和版本演进三方面详细分析:一、核心原理与...

linux 常用性能优化参数及理解

1.优化内核相关参数配置文件/etc/sysctl.conf配置方法直接将参数添加进文件每条一行.sysctl-a可以查看默认配置sysctl-p执行并检测是否有错误例如设置错了参数:[roo...

如何在 Linux 中使用 Sysctl 命令?

sysctl是一个用于配置和查询Linux内核参数的命令行工具。它通过与/proc/sys虚拟文件系统交互,允许用户在运行时动态修改内核参数。这些参数控制着系统的各种行为,包括网络设置、文件...

取消回复欢迎 发表评论: