JAVA GC(垃圾回收机制)-1

1.开篇

Arvin小编又来写技术博文啦,做个小小的笔记,顺便给一些人扫扫盲,最近对Java
的GC特别感兴趣。很早就知道在C/C++
这类语言中需要程序猿自己去操作对内存的管理 什么 alloc,
dealloc啦之类的。当初学OC的时候也有这么一章节。但是说到java很少有人会说到管理内存这块知识。java相比C语言在内存管理这块先进了好多,因为java的内存是自动管理的,光自动这个词就知道很高级有木有。但是java是怎么去创建和释放内存的呢。这个很有必要扒一扒,毕竟听说有些面试上来就问java的GC是怎么work的。还有就是这一块属于jvm的基本知识。

Java虚拟机,以下简称JVM。

最近为了严格控制控制每个java程序在mesos上的资源占用,通过cgroup对cpu&mem做了严格限制,这样设置对整个mesos-slave机器起到了保护作用,但是最近遇到服务经常由于oom被kill
-9, 个别服务会影响用户体验。为了解决这个问题,专门对java
Heap和mesos分配的内存做了调优。经过调整后,线上节省了75G的内存

2.预备知识

这篇文章只要是为后面的GC分析来做基础知识扫盲的,主要是讲jvm的内存分配。以前提到过jvm的内存就分2块
一个栈一个堆,其实这个是错的,没有这么简单,还是有点小复杂的,好了来扒一扒jvm的内存

JVM在执行java程序的过程中会把它所管理的内存划分为若干个区域。

==================

1.结构

图片 1

这张图片表明了,当运行java程序的时候
jvm会产生的内存结构,而我们平时所说的stack 和heap 就是对应的jvm
stack和heap(heap中的新生代和老年代这篇文章中不介绍,后面一篇GC分析的时候
会去详细介绍,目前就把他看成jvm就好啦)

这些区域有各自的生命周期。有的依赖于JVM,有的依赖于用户线程。

JVM Memory Component

图片 2

JVM-Memory-Area-Parts.jpg

  • Heap: The heap is the runtime data area from which memory for
    all class instances and arrays is allocated.

    How to determine a proper java Heap size

    • Profile the service (what it does), estimate the request
      throuput

    • See if the service needs to load the 3rd party date file (such
      as the robot training datasets, the dataset size is prety
      large), if yes, the the -Xmx must be larger than the dataset
      size

    • Configure GC, watch the heap value after each Full GC, that
      value is the lowest value you should set.

      1. How to config gc in java application
      
      GC_LOG_FILE='service-gc.log' 
      
      java -jar  -verbose:gc -XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:MetaspaceSize=100m  -Xloggc:$GC_LOG_FILE 
       -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=10M 
       package.jar
      
       the gc.log output:
      
       2017-07-28T05:59:17.749+0800: 49606.298: [Full GC (Ergonomics) [PSYoungGen: 288K->0K(348672K)] [ParOldGen: 699337K->75536K(699392K)] 699625K->75536K(1048064K), [Metaspace: 73744K->73744K(1116160K)], 0.1417127 secs] [Times: user=0.42 sys=0.00, real=0.14 secs]
      

2017-07-28T08:55:43.627+0800: 60192.176: [Full GC (Ergonomics)
[PSYoungGen: 256K->0K(348672K)] [ParOldGen:
699270K->72322K(699392K)] 699526K->72322K(1048064K), [Metaspace:
73764K->73764K(1116160K)], 0.1451565 secs] [Times: user=0.43
sys=0.00, real=0.14 secs]
2017-07-28T11:37:47.821+0800: 69916.370: [Full GC (Ergonomics)
[PSYoungGen: 384K->0K(347648K)] [ParOldGen:
699259K->73371K(699392K)] 699643K->73371K(1047040K), [Metaspace:
73894K->73894K(1116160K)], 0.1603913 secs] [Times: user=0.48
sys=0.00, real=0.16 secs]
2017-07-28T14:22:50.322+0800: 79818.872: [Full GC (Ergonomics)
[PSYoungGen: 416K->0K(348672K)] [ParOldGen:
699275K->73551K(699392K)] 699691K->73551K(1048064K), [Metaspace:
73942K->73918K(1116160K)], 0.1654482 secs] [Times: user=0.49
sys=0.00, real=0.17 secs]

   ```

  **In aboue gc log, the service -Xmx is set 1024M, the OldGen in heap changes from  699275K->73551K(699392K), so the full gc collected almost 620M memory, to tune this value we should set the -Xmx larger than 70M (690M - 620M), in this case, we can try to set it as 520M
  `-Xms=512m -Xmx=512m`, then keep watching the gc log to determine if 512m is enough, if this setting is low, OOM error will occur**
  • Method area: Method area is created on virtual machine startup,
    shared among all java virtual machine threads and it is logically
    part of heap area. It stores per-class structures such as the
    run-time constant pool, field and method data, and the code for
    methods and constructors.

  • Stack (-Xss: default value 1024K): holds local variables and
    partial results, and plays a part in method invocation and return.
    Once a thread is created, it will hold 1024K memory at most, and
    this can be dynamically expanded, so it means each thread might
    occupy 1K ~ 1024K, the size depends on the thread function

    How to determine a proper java stack size

    • Check the thread count of the jvm process.

        e.g: java pid is 26065
      
        cat /proc/26065/status  |grep Threads
        Threads:   1569
      
        This java process has 1569 threads, ease thread takes 1k ~ 1024K memory
      
    • Estimate the stack size as per the threads count

        This is really not straightforward, it depends on what the thread does and how it handles the data, but at least each thread won't take more than 1M, if it does, a StackOverfowError will thrown. For this service instance, it occupies 2.8G mem in total (2G is for Heap), so each thread takes 0.5M on average. 
      

Notes: As per above result, we set -Xms=2048m -Xmx=2048m, and limit the mesos memory as 4096m, if there are more concurrent requests, we can increase mesos limited memory

  • Native Method: full gc will call native method, will use certain
    amount of memory, this will only take tiny part of the jvm memory

  • pc (Program counter) register: Each Java Virtual Machine thread
    has its own pc (program counter) register. At any point, each Java
    Virtual Machine thread is executing the code of a single method,
    namely the current method (§2.6) for that thread. If that method is
    not native, the pc register contains the address of the Java Virtual
    Machine instruction currently being executed. If the method
    currently being executed by the thread is native, the value of the
    Java Virtual Machine’s pc register is undefined.

  • Summary: Basically JVM memory size = Heap + Stack. Keep monitoring
    the full gc and decide the reasonalbe heap value.

Refrence:
http://howtodoinjava.com/core-java/garbage-collection/jvm-memory-model-structure-and-components/

1)程序计数器(Program counter Register)

The Java Virtual Machine can support many threads of execution at
once. Each Java Virtual Machine thread has its own pc (program
counter) register. At any point, each Java Virtual Machine thread is
executing the code of a single method, namely the current method for
that thread. If that method is not native, the pc register contains
the address of the Java Virtual Machine instruction currently being
executed. If themethodcurrently being executed by the thread is native
, the value of the Java Virtual Machine’s pc register is undefined.
The Java Virtual Machine’s pc register is wide enough to hold a
returnAddress or a native pointer on the specific platform.

java官网给的解释,学过汇编的小伙伴应该知道cpu中的pc register
用来存储指令的地址。 其实java中的pc
register的原理和汇编中的不一样但是做的是同一件事,就是记录了当前在运行指令的地址。如果java程序运行的是native
language的指令则pc 里面存的是未定义。
其实pc的大小可以忽略不计因为里面存的数据量太小了。重点是要注意一下,pc
register是线程私有的,所谓的线程私有就是每一个线程有一个对应的pc
register,所以只有线程开始的时候 pc reigster才会创建,线程结束了 pc
register自然就木有了。

6块区域组成。

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website