7.JVM调优-方法区,堆,栈调优详解
通常我们都知道在堆空间新生代Eden区满了,会触发minor GC, 在老年代满了会触发full GC, 触发full GC会导致Stop The World, 那你们知道还有一个区域满了一会触发Full GC么?而且这个区域满了会直接影响我们的开发效率。
一、方法区参数调优
我们可以对运行时数据区的内存进行参数设置. 这是jvm调优的重点. 参数的变化将影响到整体效率
核心参数设置如下:
java -Xms2048M -Xmx1024M -Xss512k -XX:MetaspaceSize=256M -XX:MaxMetaspaceSize=256M -jar microservice-eureka-server.jar
这是一个通用的设置。图中具体含义如下:
- -Xms:堆空间最小值
- -Xmx:堆空间最大值
- -Xmn:新生代占堆空间的大小
- -XX:MetaspaceSize:方法区(元空间)初始值
- -XX:MaxMetaspaceSize:方法区(元空间)最大值
- -Xss:每一个线程的空间大小
下面主要研究方法区参数设置
1. 方法区(元空间)参数设置
在jdk8之前有个区域叫做永久代, 在jdk8及以后改名字了, 叫做元空间. 这块内存空间占用的是直接的物理内存.
元空间有一个特点: 可以动态扩容。如果, 我们没有设置元空间的上限, 那么他可以扩大到整个内存. 比如内存条是8G的, 堆和栈分配了4G的空间, 那么元空间最多可以使用4G。
我们可以通过参数来设置使用的元空间内存。
对于64位的JVM来说, 元空间默认大小是21M, 元空间的默认最大值是无上限的, 他的上限就是内存空间
- -XX:MetaspaceSize: 元空间的初始空间大小, 以字节位单位, 默认是21M,达到该值就会触发full GC, 同时收集器会对该值进行调整, 如果释放了大量的空间, 就适当降低该值, 如果释放了很少的空间, 提升该值,但最到不超过-XX:MaxMetaspaceSize设置的值
比如:
初始值是21M, 第一次回收了20M, 那么只有1M没有被回收, 下一次, 元空间会自动调整大小, 可能会调整到15M
初始大小依然是21M, 第二次回收发现回收了1M, 有20M没有被回收, 他就会自动扩大空间, 可能扩大到30M,也可能是40M
- -XX:MaxMetaspaceSize: 设置元空间的最大值, 默认是-1, 即不限制, 或者说只受限于本地内存的大小
由于调整元空间的大小需要full GC, 这是非常昂贵的操作, 如果应用在启动的时候发生大量的full GC, 通常都是由于永久代或元空间发生了大小的调整, 基于这种情况, 一般建议在JVM参数中将-XX:MetaspaceSize和-XX:MaxMetaspaceSize设置成一样的值, 并设置的比初始值还要大, 对于8G物理内存的机器来说, 一般会将这两个值设置为256M或者512M都可以
2. 建议设置元空间值, 如果不设置会怎么样?
不设置元空间默认就是21M, 很容易就会放满, 通常我们的war可能都是几十M, 甚至几个G. 如果我们在启动程序的时候, 会启动几分钟. 这很有可能是没有设置元空间的大小.
放满后会发生full GC, 然后在扩大一点元空间, 扩大到25M, 重新开始, 过了一会又放满了, 再次full GC, 在扩大一点, 元空间扩大到30M, 就这样一直发生full GC, 然后一直扩大元空间, 直到扩大的元空间大小合适, 不再发生full gc, 程序才会正常启动运行. 这是个很耗时耗性能的操作, 这样的full GC也是没有必要的.
如果项目启动较慢,多次重复启动,考虑是不是元空间设置不合理,或者内存不够导致。
二. 线程栈参数调优
-Xss512k:设置栈空间参数的
这个参数就是用来设置栈空间的. 他是设置的一个线程栈占用的空间, 一个程序启动后可能有多个线程栈, 那么他们占用的空间都是512k。
一个程序启动以后,系统为其分配的栈空间是固定的。理论上来说,如果每一个线程占用的空间少,那么就能分配更多的线程。否则则相反。但这也不是确定的,还有和系统的cpu,内存有关系。
当线程分配的空间用完的时候,就会抛出栈溢出异常。下面来看一个例子
package com.lxl.jvm;
public class StackOverflowTest {
/**
* jvm 设置-Xss128M, (默认是1M)
*/
static int count = 0;
public static void redo(){
count ++;
redo();
}
public static void main(String[] args) {
try {
redo();
}catch (Throwable e) {
e.printStackTrace();
System.out.println(count);
}
}
}
这里定义了一个变量count, main方法里调用了redo()方法. 当我们执行main方法的时候, 线程栈模型是什么样的呢?
当程序执行到main方法的时候, 会在线程栈中开辟一个main方法的栈帧
继续执行, 执行到redo()的时候, 会在线程栈在开辟一块redo方法栈帧
redo方法里又调用了redo方法. 继续开辟一块redo方法栈帧,
.......
栈帧是占用内存空间的. 总有一个时刻会把栈内存消耗完. 就会报栈内存溢出了
我们看到程序一共运行了16979次发生了栈溢出.
当栈空间设置的小一些呢?比如256k
我们运行看效果
当运行到2079次的时候, 发生了栈溢出。
7.JVM调优-方法区,堆,栈调优详解的更多相关文章
- [二]Java虚拟机 jvm内存结构 运行时数据内存 class文件与jvm内存结构的映射 jvm数据类型 虚拟机栈 方法区 堆 含义
前言简介 class文件是源代码经过编译后的一种平台中立的格式 里面包含了虚拟机运行所需要的所有信息,相当于 JVM的机器语言 JVM全称是Java Virtual Machine ,既然是虚拟机, ...
- JVM存储位置分配——java中局部变量、实例变量和静态变量在方法区、栈内存、堆内存中的分配
Java中的变量根据不同的标准可以分为两类,以其引用的数据类型的不同来划分可分为“原始数据类型变量和引用数据类型变量”,以其作用范围的不同来区分可分为“局部变量,实例变量和静态变量”. 根据“Java ...
- 牛客网Java刷题知识点之内存的划分(寄存器、本地方法区、方法区、栈内存和堆内存)
不多说,直接上干货! 其中 1)程序计数器:用于指示当前线程所执行的字节码执行到了第几行,可以理解为当前线程的行号指示器.每个计数器志勇赖记录一个线程的行号,所以它是线程私有的. ...
- Java中局部变量、实例变量和静态变量在方法区、栈内存、堆内存中的分配
转自:https://blog.csdn.net/leunging/article/details/80599282 感谢CSDN博主「leunging」的总结分享 ———————————————— ...
- 常量池、perm(持久代)、方法区、栈
常量池.perm(持久代).方法区.栈 常量池指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据. 除了包含代码中所定义的各种基本类型(如:int.long等等)和对象型(如St ...
- JVM中的方法区
JVM中的方法区 方法区存储什么? 用于存储已被虚拟机加载的类型信息.常量.静态变量.即时编译器编译后的代码缓存 1.类型信息 对每个加载的类型(类class.接口interface.枚举.注解)jv ...
- C/C++堆、栈及静态数据区详解
转自:https://www.cnblogs.com/hanyonglu/archive/2011/04/12/2014212.html 做略微修改 C/C++堆.栈及静态数据区详解 本文介绍C ...
- “全栈2019”Java第九十七章:在方法中访问局部内部类成员详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- 详解C#泛型(二) 获取C#中方法的执行时间及其代码注入 详解C#泛型(一) 详解C#委托和事件(二) 详解C#特性和反射(四) 记一次.net core调用SOAP接口遇到的问题 C# WebRequest.Create 锚点“#”字符问题 根据内容来产生一个二维码
详解C#泛型(二) 一.自定义泛型方法(Generic Method),将类型参数用作参数列表或返回值的类型: void MyFunc<T>() //声明具有一个类型参数的泛型方法 { ...
随机推荐
- jsp中核心标签使用
<%@ page language="java" import="java.util.*, java.lang.*" pageEncoding=" ...
- windows下mysql5.7.17配置
1.官网下载mysql5.7.17 64位 https://dev.mysql.com/downloads/mysql/ 2.安装完解压到E盘主目录下,改文件名为mysql 3.配置环境变量 我的电脑 ...
- 基于CentOS7.x Linux操作系统,从0开始构建一套Docker虚拟化平台,使用二进制Tar包方式,部署的步骤和方法如下:
#配置centos7的yum源#建议阿里源#链接:https://yq.aliyun.com/articles/525282?type=2#从Docker官网下载软件包: ls -l docker-1 ...
- uni-app 小程序从零开始的开发流程
前言 本文基于 HBuilderX 3.1.22 + 微信开发者工具 1.05.2106300为主要内容进行说明. 文档版本:1.0.0 更新时间:2021-09-03 15:32 一.准备 uni- ...
- GUI容器之布局管理器
布局管理器 布局管理器:frame.setLayout(); 默认值为new flowLayout() 流式布局 frame.setLayout(new FlowLayout(FlowLayout.R ...
- HTB Hack The Box -- Oopsiec
信息收集 开放了22ssh,80端口,其中ssh有弱口令爆破端口 先打开网页,然后进行目录爆破,在这期间先看一下网页的大概信息 没爆到什么有用的东西,但是有uploads文件夹说明是不是说明有文件上传 ...
- Python - pip 批量更新
pip 常用命令 https://www.cnblogs.com/poloyy/p/15170968.html pip list 结合 Linux 命令 pip list 命令可以查询已安装的库,结合 ...
- Selenium系列(22) - 通过selenium控制浏览器滚动条的几种方式
如果你还想从头学起Selenium,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1680176.html 其次,如果你不懂前端基础知识, ...
- MongoDB(3)- Database 数据库相关
Database MongoDB 将数据记录存储为文档(特别是 BSON 文档) 这些文档在集合中聚集在一起 数据库存储一个或多个文档集合. 在 MongoDB 里面存在数据库的概念,但没有模式 Sh ...
- 查看elasticsearch版本的方法
查看elasticsearch版本的方法: 1.elasticsearch已经启动的情况下 使用curl -XGET localhost:9200命令查看: "version" : ...