java内存结构学习

本文详细介绍了Java内存结构,包括线程私有的栈、本地方法栈、程序计数器,以及线程共享的堆和方法区。讲解了类加载过程的加载、链接(验证、准备、解析)和初始化阶段。同时,探讨了JVM调优,如新生代与老年代的设置、栈内存配置以及如何使用工具排查内存泄漏和线程问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java内存结构学习

方法区,堆,本地方法栈,程序技术器,栈

线程私有:

栈:为执行java方法服务。

本地方法栈:主要是native方法。

程序计数器:主要存放当前执行指令的地址

线程共享:

堆:存放类的实例信息,绝大多数创建的实例对象会存放在这里。

方法区:主要存放类的信息,常量,静态变量。垃圾回收器针对这块的回收主要是针对常量池和类的卸载。

jvm只是规定了有方法区这么个概念和它的作用,并没有规定如何去实现它,jdk8永久代被废弃了,永久代替换成本地内存。

jvm类加载过程:

(1)加载:jvm去查找字节流(.class文件),将.class文件中的二进制数据读入内存,放在运行时区域的方法区内,然后在堆中创建java.lang.Class对象,用来封装类在方法区的数据结构。

(2)链接:

1.验证:验证加载进来的二进制数据是否满足虚拟机规范,不会造成安全错误。

2.准备:负责为类的静态成员分配内存,并设置初始值。

3.解析:将类的二进制数据中的符号引用替换成直接引用。

符号引用:即一个字符串。

直接引用:可以理解为一个内存地址。

(3)初始化:

初始化,则是为标记为常量值的字段赋值的过程,只对static修饰的变量和语句进行初始化。

 

jvm调优:

(1)设置新生代和老年代的:

设置原则:

a.尽可能的让对象在新生代被回收,让对象尽量的存活在survivor,使之在新生代被回收。

b.如果内存不够,则增大survivor区,减少eden区。

设置参数:

-Xmx:设置堆最大可用值

-Xms:设置堆初始值

-Xmn:设置新生代最大可用值

-XX:newRatio:设置新生代与新生代的比例

-XX:SurvivorRatio 设置Eden与survivor的比例

(2)栈内存设置

-Xss1024k:设置每个线程的堆栈大小

栈内存设置过小,则容易栈溢出,设置过大,就会,线程数量就不好控制,如果是多线程的应用,容易造成内存溢出。

 

总结常用的jvm排查工具:

(1)查看哪些对象占用内存。

现象:查看gc.log的日志,发现full gc很频繁 

思路:是否发生了内存泄露,要知道内存泄露就最好先知道是哪些对象占用了内存,并且长时间没有释放。

排查:

a.查看jvm内存查看(gc日志),发现老年代占用内存6.8G,总的堆内存大小为7.1G,使用占比95%,也就是老年代很容易满,很容易触发full gc。

b.定位是哪些类在占用内存

gcore 进程pid(gcore产生core文件,这比直接使用使用jmap dump快的多,可以避免对线上服务造成影响,core文件的大小跟进程使用的堆大小一样大。)

 

jmap dump;format=b,file=heap.hrpof.bin ../bin/java core.xxxx(将core文件转换成bin文件,hprof文件跟进程实际的堆内存一样大)

使用eclipse的MAT工具分析出持有的最大的几个类,假设类A,类B

由于从数据库查询,从文件中查询数据,从hbase中查询数据,缓存到A的字段属性中,每次操作时间很长,用空间换时间。

c.临时处理:

重新规划老年代的比例。

-Xms太低,导致内存频繁申请和回收。

d.作业迁移,定时计算。

(2)查看线程占用应用的时间长短。

现象:后台java进程占用CPU过高

思路;是否有线程一直没有释放,查看线程占用时间。

排查:

a.ps  -mp pid -o THREAD,tid,time 查看进程信息

找到耗时最高的线程xxx,占用cpu yyy小时

b.print “%x\d” tid

将需要打印的线程id转换为16进制格式

c.jstack pid| grep tid -A 60

打印线程的堆栈信息 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值