JVM之参数分配(全面讲解)

2025-05-29 0 52

一、堆参数设置

-xx:+printgc 使用这个参数,虚拟机启动后,只要遇到gc就会打印日志

-xx:+useserialgc 配置串行回收器

-xx:+printgcdetails 可以查看详细信息,包括各个区的情况

-xms:设置java程序启动时初始化堆大小

-xmx:设置java程序能获得最大的堆大小

-xmx20m -xms5m -xx:+printcommandlineflags:可以将隐式或者显示传给虚拟机的参数输出

在实际工作中,我们可以直接将初始的堆大小与最大堆大小设置相等,这样的好处是可以减少程序运行时的垃圾回收次数,从而提高性能。

配置运行时参数-xx:+printgc -xms5m -xmx20m -xx:+useserialgc -xx:+printgcdetails -xx:+printcommandlineflags

运行一下demo:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26
package com.ietree.basicskill.jvm;

public class demo01 {

public static void main(string[] args) {

// -xx:+printgc -xms5m -xmx20m -xx:+useserialgc -xx:+printgcdetails -xx:+printcommandlineflags

//查看gc信息

system.out.println("max memory:" + runtime.getruntime().maxmemory());

system.out.println("free memory:" + runtime.getruntime().freememory());

system.out.println("total memory:" + runtime.getruntime().totalmemory());

byte[] b1 = new byte[1*1024*1024];

system.out.println("分配了1m");

system.out.println("max memory:" + runtime.getruntime().maxmemory());

system.out.println("free memory:" + runtime.getruntime().freememory());

system.out.println("total memory:" + runtime.getruntime().totalmemory());

byte[] b2 = new byte[4*1024*1024];

system.out.println("分配了4m");

system.out.println("max memory:" + runtime.getruntime().maxmemory());

system.out.println("free memory:" + runtime.getruntime().freememory());

system.out.println("total memory:" + runtime.getruntime().totalmemory());

}

}

程序输出:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23
-xx:initialheapsize=5242880 -xx:maxheapsize=20971520 -xx:+printcommandlineflags -xx:+printgc -xx:+printgcdetails -xx:+usecompressedclasspointers -xx:+usecompressedoops -xx:-uselargepagesindividualallocation -xx:+useserialgc

max memory:20316160

free memory:5286032

total memory:6094848

[gc (allocation failure) [defnew: 789k->191k(1856k), 0.0026441 secs] 789k->530k(5952k), 0.0027627 secs] [times: user=0.00 sys=0.00, real=0.00 secs]

分配了1m

max memory:20316160

free memory:4469352

total memory:6094848

[gc (allocation failure) [defnew: 1249k->0k(1856k), 0.0022285 secs][tenured: 1554k->1554k(4096k), 0.0031394 secs] 1587k->1554k(5952k), [metaspace: 2597k->2597k(1056768k)], 0.0054980 secs] [times: user=0.00 sys=0.00, real=0.01 secs]

分配了4m

max memory:20316160

free memory:4538184

total memory:10358784

heap

def new generation total 1920k, used 68k [0x00000000fec00000, 0x00000000fee10000, 0x00000000ff2a0000)

eden space 1728k, 3% used [0x00000000fec00000, 0x00000000fec113e0, 0x00000000fedb0000)

from space 192k, 0% used [0x00000000fedb0000, 0x00000000fedb0000, 0x00000000fede0000)

to space 192k, 0% used [0x00000000fede0000, 0x00000000fede0000, 0x00000000fee10000)

tenured generation total 8196k, used 5650k [0x00000000ff2a0000, 0x00000000ffaa1000, 0x0000000100000000)

the space 8196k, 68% used [0x00000000ff2a0000, 0x00000000ff824888, 0x00000000ff824a00, 0x00000000ffaa1000)

metaspace used 2603k, capacity 4486k, committed 4864k, reserved 1056768k

class space used 288k, capacity 386k, committed 512k, reserved 1048576k

在此程序输出的结果中,可以看到堆的详细信息,比如可以看到它的新生代信息、老年代信息、永久区信息等。

二、新生代参数配置

-xmn:可以设置新生代的大小,设置一个比较大的新生代会减少老年代的大小,这个参数对系统性能以及gc行为有很大的影响,新生代大小一般会设置整个堆空间的1/3到1/4左右。

xx:survivorratio:用来设置新生代中eden空间和from/to空间的比例。含义:-xx:survivorratio=eden/from=eden/to。
不同的堆分布情况,对系统执行会产生一定的影响,在实际工作中,应该根据系统的特点做出合理的配置,基本策略:尽可能将对象预留在新生代,减少老年代的gc次数。

除了可以设置新生代的绝对大小(-xmn),还可以使用(-xx:newratio)设置新生代和老年代的比例:-xx:newratio=老年代/新生代。

配置运行时参数

-xms20m -xmx20m -xmn1m -xx:survivorratio=2 -xx:+printgcdetails
-xx:+useserialgc

运行demo:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22
package com.ietree.basicskill.jvm;

public class demo2 {

public static void main(string[] args) {

// 第一次配置(eden 2 = from 1 + to 1)

// -xms20m -xmx20m -xmn1m -xx:survivorratio=2 -xx:+printgcdetails -xx:+useserialgc

// 第二次配置

// -xms20m -xmx20m -xmn7m -xx:survivorratio=2 -xx:+printgcdetails -xx:+useserialgc

// 第三次配置

// -xx:newratio=老年代/新生代

// -xms20m -xmx20m -xx:newratio=2 -xx:+printgcdetails -xx:+useserialgc

byte[] b = null;

// 连续向系统申请10mb空间

for (int i = 0; i < 10; i++) {

b = new byte[1 * 1024 * 1024];

}

}

}

程序运行结果:

?

1

2

3

4

5

6

7

8

9

10
[gc (allocation failure) [defnew: 508k->256k(768k), 0.0012770 secs] 508k->435k(20224k), 0.0013333 secs] [times: user=0.00 sys=0.00, real=0.00 secs]

heap

def new generation total 768k, used 498k [0x00000000fec00000, 0x00000000fed00000, 0x00000000fed00000)

eden space 512k, 47% used [0x00000000fec00000, 0x00000000fec3c988, 0x00000000fec80000)

from space 256k, 100% used [0x00000000fecc0000, 0x00000000fed00000, 0x00000000fed00000)

to space 256k, 0% used [0x00000000fec80000, 0x00000000fec80000, 0x00000000fecc0000)

tenured generation total 19456k, used 10419k [0x00000000fed00000, 0x0000000100000000, 0x0000000100000000)

the space 19456k, 53% used [0x00000000fed00000, 0x00000000ff72cf20, 0x00000000ff72d000, 0x0000000100000000)

metaspace used 2601k, capacity 4486k, committed 4864k, reserved 1056768k

class space used 288k, capacity 386k, committed 512k, reserved 1048576k

可以看到,在新生代种,eden区域内存是from和to区域内存的2倍。即-xx:survivorratio=2参数起了作用。

配置运行参数-xms20m -xmx20m -xx:newratio=2 -xx:+printgcdetails -xx:+useserialgc

运行以上demo可以得到一下输出:

?

1

2

3

4

5

6

7

8

9

10

11
[gc (allocation failure) [defnew: 4979k->529k(6144k), 0.0028804 secs] 4979k->1553k(19840k), 0.0029572 secs] [times: user=0.00 sys=0.00, real=0.00 secs]

[gc (allocation failure) [defnew: 5756k->0k(6144k), 0.0021035 secs] 6780k->2576k(19840k), 0.0021487 secs] [times: user=0.00 sys=0.00, real=0.00 secs]

heap

def new generation total 6144k, used 1134k [0x00000000fec00000, 0x00000000ff2a0000, 0x00000000ff2a0000)

eden space 5504k, 20% used [0x00000000fec00000, 0x00000000fed1b9d8, 0x00000000ff160000)

from space 640k, 0% used [0x00000000ff160000, 0x00000000ff160000, 0x00000000ff200000)

to space 640k, 0% used [0x00000000ff200000, 0x00000000ff200000, 0x00000000ff2a0000)

tenured generation total 13696k, used 2576k [0x00000000ff2a0000, 0x0000000100000000, 0x0000000100000000)

the space 13696k, 18% used [0x00000000ff2a0000, 0x00000000ff524140, 0x00000000ff524200, 0x0000000100000000)

metaspace used 2601k, capacity 4486k, committed 4864k, reserved 1056768k

class space used 288k, capacity 386k, committed 512k, reserved 1048576k

发现tenured generation老年代的内存是new generation 新生代内存的2倍。

三、堆溢出参数配置

在java程序的运行过程中,如果对空间不足,则会抛出内存溢出的错误(out of memory)oom,一旦这类问题发生在生产环境,则可能引起严重的业务中断,java虚拟机提供了-xx:+heapdumponoutofmemoryerror,
使用该参数可以在内存溢出时导出整个堆信息,与之配合使用的还有参数-xx:heapdumppath,可以设置导出堆的存放路径。
内存分析工具:memory analyzer

配置运行时参数-xms1m -xmx1m -xx:+heapdumponoutofmemoryerror -xx:heapdumppath=d:/demo3.dump

运行demo:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14
package com.ietree.basicskill.jvm;

import java.util.vector;

public class demo3 {

public static void main(string[] args) {

// -xms1m -xmx1m -xx:+heapdumponoutofmemoryerror -xx:heapdumppath=d:/demo3.dump

// 堆内存溢出

vector v = new vector();

for (int i = 0; i < 5; i++) {

v.add(new byte[1 * 1024 * 1024]);

}

}

}

程序输出的结果:

?

1

2

3

4

5
java.lang.outofmemoryerror: java heap space

dumping heap to d:/demo3.dump ...

heap dump file created [1219372 bytes in 0.009 secs]

exception in thread "main" java.lang.outofmemoryerror: java heap space

at com.ietree.basicskill.jvm.demo3.main(demo3.java:11)

在d:/demo3.dump可以找到对应的文件,使用内存分析工具(memory analyzer)打开:

如图:

JVM之参数分配(全面讲解)

四、栈参数配置

java虚拟机提供了参数-xss来指定线程的最大栈空间,整个参数也直接决定了函数可调用的最大深度。

配置运行时参数-xss1m

运行demo:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23
package com.ietree.basicskill.jvm;

public class demo4 {

// -xss1m

// -xss5m

// 栈调用深度

private static int count;

public static void recursion() {

count++;

recursion();

}

public static void main(string[] args) {

try {

recursion();

} catch (throwable t) {

system.out.println("调用最大深入:" + count);

t.printstacktrace();

}

}

}

程序输出:

?

1

2

3

4

5

6

7

8

9

10

11
调用最大深入:20557

java.lang.stackoverflowerror

at com.ietree.basicskill.jvm.demo4.recursion(demo4.java:12)

at com.ietree.basicskill.jvm.demo4.recursion(demo4.java:12)

at com.ietree.basicskill.jvm.demo4.recursion(demo4.java:12)

at com.ietree.basicskill.jvm.demo4.recursion(demo4.java:12)

at com.ietree.basicskill.jvm.demo4.recursion(demo4.java:12)

at com.ietree.basicskill.jvm.demo4.recursion(demo4.java:12)

at com.ietree.basicskill.jvm.demo4.recursion(demo4.java:12)

at com.ietree.basicskill.jvm.demo4.recursion(demo4.java:12)

......

五、方法区参数配置

和java堆一样,方法区是一块所有线程共享的内存区域,它用于保存系统的类信息,方法区(永久区)可以保存多少信息可以对其进行配置,在默认情况下,-xx:maxpermsize为64m,
如果系统运行时生产大量的类,就需要设置一个相对合适的方法区,以免出现永久区内存溢出的问题。

-xx:permsize=64m -xx:maxpermsize=64m

六、直接内存参数配置

直接内存也是java程序中非常重要的组成部分,特别是广泛用在nio中,直接内存跳过了java堆,使用java程序可以直接访问原生堆空间,因此在一定程度上加快了内存空间的访问速度。

但是说直接内存一定就可以提高内存访问速度也不见得,具体情况具体分析。

相关配置参数-xx:maxdirectmemorysize,如果不设置,默认值为最大堆空间,即-xmx。直接内存使用达到上限时,就会触发垃圾回收,如果不能有效的释放空间,就会引起系统的oom。

七、对象进入老年代的参数配置

一般而言,对象首次创建会被放置在新生代的eden区,如果没有gc介入,则对象不会离开eden区,那么eden区的对象如何进入老年代呢?

通常情况下,只要对象的年龄达到一定的大小,就会自动离开年轻代进入老年代,对象年龄是由对象经历数次gc决定的,在新生代每次gc之后如果对象没有被回收,则年龄加1。

虚拟机提供了一个参数来控制新生代对象的最大年龄,当超过这个年龄范围就会晋升老年代。

-xx:maxtenuringthreshold,默认情况下为15

配置运行时参数-xmx64m -xms64m -xx:+printgcdetails

运行demo:

?

1

2

3

4

5

6

7

8

9

10

11

12
package com.ietree.basicskill.jvm;

public class demo5 {

public static void main(string[] args) {

// 初始的对象在eden区

// 参数:-xmx64m -xms64m -xx:+printgcdetails

for (int i = 0; i < 5; i++) {

byte[] b = new byte[1024 * 1024];

}

}

}

程序输出:

?

1

2

3

4

5

6

7

8

9
heap

psyounggen total 18944k, used 6759k [0x00000000feb00000, 0x0000000100000000, 0x0000000100000000)

eden space 16384k, 41% used [0x00000000feb00000,0x00000000ff199db8,0x00000000ffb00000)

from space 2560k, 0% used [0x00000000ffd80000,0x00000000ffd80000,0x0000000100000000)

to space 2560k, 0% used [0x00000000ffb00000,0x00000000ffb00000,0x00000000ffd80000)

paroldgen total 44032k, used 0k [0x00000000fc000000, 0x00000000feb00000, 0x00000000feb00000)

object space 44032k, 0% used [0x00000000fc000000,0x00000000fc000000,0x00000000feb00000)

metaspace used 2601k, capacity 4486k, committed 4864k, reserved 1056768k

class space used 288k, capacity 386k, committed 512k, reserved 1048576k

结论:对象首次创建会被放置在新生代的eden区,因此输出结果中from和to区都为0%。

根据设置maxtenuringthreshold参数,可以指定新生代对象经过多少次回收后进入老年代。另外,大对象新生代eden区无法装入时,也会直接进入老年代。

jvm里有个参数可以设置对象的大小超过在指定的大小之后,直接晋升老年代。
-xx:pretenuresizethreshold=15

参数:-xmx1024m -xms1024m -xx:+useserialgc -xx:maxtenuringthreshold=15 -xx:+printgcdetails

使用pretenuresizethreshold可以进行指定进入老年代的对象大小,但是要注意tlab区域优先分配空间。虚拟机对于体积不大的对象 会优先把数据分配到tlab区域中,因此就失去了在老年代分配的机会.

参数:-xmx30m -xms30m -xx:+useserialgc -xx:+printgcdetails -xx:pretenuresizethreshold=1000 -xx:-usetlab

八、tlab参数配置

tlab全称是thread local allocation buffer即线程本地分配缓存,从名字上看是一个线程专用的内存分配区域,是为了加速对象分配对象而生的。

每一个线程都会产生一个tlab,该线程独享的工作区域,java虚拟机使用这种tlab区来避免多线程冲突问题,提高了对象分配的效率。

tlab空间一般不会太大,当大对象无法在tlab分配时,则会直接分配到堆上。

-xx:+usetlab使用tlab

-xx:+tlabsize设置tlab大小

-xx:tlabrefillwastefraction设置维护进入tlab空间的单个对象大小,它是一个比例值,默认为64,即如果对象大于整个空间的1/64,则在堆创建对象。

-xx:+printtlab查看tlab信息

-xx:resizetlab自调整tlabrefillwastefraction阈值。

参数:-xx:+usetlab -xx:+printtlab -xx:+printgc -xx:tlabsize=102400 -xx:-resizetlab -xx:tlabrefillwastefraction=100 -xx:-doescapeanalysis -server

以上这篇jvm之参数分配(全面讲解)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持快网idc。

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 JVM之参数分配(全面讲解) https://www.kuaiidc.com/115889.html

相关文章

发表评论
暂无评论