java内存区域

内存区域

程序计数器  数据线程独占区每一个线程都有一个单独的程序计数器。此区域是唯一一个在java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。

虚拟机栈     描述的是java方法执行的动态内存模型

        栈帧:虚拟机每个线程都有一个固定的大小由参数Xss分配。每个方法执行都会创建一个栈帧伴随着方法从创建到执行完成 用于存储变量表,操作数栈,动态链接每个方法从调用直至执行完成的过程就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。 当栈帧满了之后如果依旧会有栈继续进入则有StackOverFlowError异常如果这时未给栈帧设置大小则OutOfMemory,如递归调用    

        局部变量表  

虚拟机堆   大部分java对象实例

方法区    线程共享的情况下虚拟机加载的类信息,常量,静态变量即编译器编译后的代码等数据

         运行时常量池    

对象的创建     

      new 类名  -->  根据new的参数在常量池中定位一个类的符号引用  --> 如果没有找到这个符号引用说明类还没有被加载则进行类的加载解析和初始化 --> 虚拟机为对象分配内存(堆中) -->  将分配的内存初始化为零值  --> 调用对象的init方法

 

内存分配策略

优先分配到eden
大对象直接分配到老年代
长期存活的对象分配到老年代
空间分配担保
动态对象年龄判断

在运行参数(idea -- VM options)中设置 -verbose:gc -XX:+PrintGCDetails  ( -XX:+UseSerialGC ) 并选择使用指定的GC的收集器控制台打印内存分配的信息如下:

Heap
 PSYoungGen      total 38400K, used 9429K [0x00000000d5f80000, 0x00000000d8a00000, 0x0000000100000000)
  eden space 33280K, 28% used [0x00000000d5f80000,0x00000000d68b56b0,0x00000000d8000000)
  from space 5120K, 0% used [0x00000000d8500000,0x00000000d8500000,0x00000000d8a00000)
  to   space 5120K, 0% used [0x00000000d8000000,0x00000000d8000000,0x00000000d8500000)
 ParOldGen       total 87552K, used 0K [0x0000000081e00000, 0x0000000087380000, 0x00000000d5f80000)
  object space 87552K, 0% used [0x0000000081e00000,0x0000000081e00000,0x0000000087380000)
 Metaspace       used 3388K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 371K, capacity 388K, committed 512K, reserved 1048576K

从而可以看出在一定的标准下优先分配到eden区域。

现在设置eden区域的大小为8M: -Xmx20M  -Xmn10M  -XX:SurvivorRatio=8M。当存放如下内存时

        byte[] b1 = new byte[2 * 1024 * 1024];
        byte[] b2 = new byte[2 * 1024 * 1024];
        byte[] b3 = new byte[2 * 1024 * 1024];
        byte[] b4 = new byte[4 * 1024 * 1024];


[GC (Allocation Failure) [DefNew: 7986K->1023K(9216K), 0.0036998 secs] 7986K->5254K(19456K), 0.0037303 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] 
[Full GC (System.gc()) [Tenured: 4230K->6278K(10240K), 0.0034140 secs] 11638K->11362K(19456K), [Metaspace: 3420K->3420K(1056768K)], 0.0034400 secs] [Times: user=0.02 sys=0.00, real=0.00 secs] 
Heap
 def new generation   total 9216K, used 5385K [0x00000000fec00000, 0x00000000ff600000, 0x00000000ff600000)
  eden space 8192K,  65% used [0x00000000fec00000, 0x00000000ff142500, 0x00000000ff400000)
  from space 1024K,   0% used [0x00000000ff500000, 0x00000000ff500000, 0x00000000ff600000)
  to   space 1024K,   0% used [0x00000000ff400000, 0x00000000ff400000, 0x00000000ff500000)
 tenured generation   total 10240K, used 6278K [0x00000000ff600000, 0x0000000100000000, 0x0000000100000000)
   the space 10240K,  61% used [0x00000000ff600000, 0x00000000ffc21930, 0x00000000ffc21a00, 0x0000000100000000)
 Metaspace       used 3441K, capacity 4496K, committed 4864K, reserved 1056768K
  class space    used 372K, capacity 388K, committed 512K, reserved 1048576K

在为新生代分配10M内存eden区域分配8M之后,b1b2b3进入eden还剩余2M故b4无法进入只能向老年代借用内存发生第一次GC。这次GC发生在新生代时间较短相对也较为频繁。当b4再次进入时再次分配到eden区域。

大对象直接进入老年代   -XX:PretenureSizeThreshold 设置大对象的大小

空间分配担保  -XX:+HandlerPromotionFailure 满足eden是否能存放下并且开启了此参数(+ / -)

逃逸分析与栈上分配    分析对象的作用域只有发生在方法体内部才能认为没有发生逃逸,没有发生逃逸则资源直接分配到栈上。无论是存在返回值还是在方法体内引用了成员变量都认为存在逃逸。如下几种情况都认为是发生了逃逸

static V global_v;
public void a_method(){
 V v=b_method();
 c_method();
}
public V b_method(){
 V v=new V();
 return v;
}
public void c_method(){
 global_v=new V();
}

 

虚拟机工具

jstat

堆内存 = 年轻代 + 老年代 + 永久代 ; 年轻代 = eden区+两个Survivor区

jinfo  实时查看和调整虚拟机的各项参数

jmap  jmap -dump:format=b,file=d:\a.bin 2345下载dump文件为.bin文件。

jstack   用于生成当前时刻的线程快照,线程快照指的是当前java虚拟机内每一条线程正在执行的方法堆栈的集合生成快照的主要目的是定位线程出现长时间停顿的原因如线程间死锁,死循环,请求外部资源导致的长时间等待等。所以指定线程名字监控线程信息会对线程定位会有很大的帮助。

RUNNING  运行状态
BLOCKED  受阻塞并等待监视器锁
WATING   无限等待
TIMED_WAITING  有时限的等待另一个线程的特定操作

jstack pid  查看当前pid运行情况 

1.top 查找出哪个进程消耗的cpu高。执行top命令,默认是进程视图,其中PID是进程号
co_ad2    18   0 1817m 776m 9712 S  3.3  4.9  12:03.24 java                                                                                           
co_ad     21   0 3028m 2.5g 9432 S  1.0 16.3   6629:44 ja
这里我们分析21125这个java进程

2.top -H p 进程ID 查看当前进程中使用线程CPU最高的线程  
co_ad2    15   0 1807m 630m 9492 S  1.3  4.0   0:05.12 java                                                                                           
co_ad2_s  15   0 1360m 560m 9176 S  0.3  3.6   0:46.72 java                                                                                           

这里我们分析21233这个线程,并且注意的是,这个线程是属于21125这个进程的。 

3.打印这一时刻的堆栈信息 sudo -u admin /usr/home/java/bin/jstack -l pid > /home/log/jstack.log 
 由于jstack.log文件记录的线程ID是16进制,需要将top命令展示的线程号转换为16进制。

4. jstack查找这个线程的信息 
jstack [进程]|grep -A 10 [线程的16进制] 
即: jstack 21125|grep -A 10 52f1  

-A 10表示查找到所在行的后10行。21233用计算器转换为16进制52f1,注意字母是小写。 
结果: 
 
"http-8081-11" daemon prio=10 tid=0x00002aab049a1800 nid=0x52bb in Object.wait() [0x0000000042c75000]  
   java.lang.Thread.State: WAITING (on object monitor)  
     at java.lang.Object.wait(Native Method)  
     at java.lang.Object.wait(Object.java:485)  
     at org.apache.tomcat.util.net.JIoEndpoint$Worker.await(JIoEndpoint.java:416)  

在结果中查找52f1,可看到当前线程在做什么。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值