关于OOM 1

Problem Description

Out Of Memory (OOM) - An application displays Out of Memory errors due to memory exhaustion, either in java heap or native memory.

Memory Leak - Constant memory growth in either java heap or native memory, which will eventually end up in out of memory situation. The techniques to debug the memory leak situations are the same as the out of memory situations.

Background

Java Heap, Native Memory and Process size

Java heap – This is the memory that the JVM uses to allocate java objects. The maximum value of java heap memory is specified using –Xmx flag in the java command line. If the maximum heap size is not specified, then the limit is decided by the JVM considering factors like the amount of physical memory in the machine and the amount of free memory available at that moment. It is always recommended to specify the max java heap value.

Native memory – This is the memory that the JVM uses for its own internal operations. The amount of native memory heap that will be used by the JVM depends on the amount of code generated, threads created, memory used during GC for keeping java object information and temporary space used during code generation, optimization etc.

If there is a third party native module, it could also use the native memory. For example, native JDBC drivers allocate native memory.

The max amount of native memory is limited by the virtual process size limitation on any given OS and the amount of memory already committed for the java heap with –Xmx flag. For example, if the application can allocate a total of 3 GB and if the max java heap is 1 GB, then the max possible native memory is approximately 2 GB.

Process size – Process size will be the sum of the java heap, native memory and the memory occupied by the loaded executables and libraries. On 32 bit operating systems, the virtual address space of a process can go up to 4 GB. Out of this 4 GB, the OS kernel reserves some part for itself (typically 1 – 2 GB). The remaining is available for the application.

Windows – By default, 2 GB is available for the application and 2 GB is reserved for Kernel’s use. However, on some variants of Windows, there is a /3GB switch which can be used to change this ratio such that the application gets 3 GB.

RH Linux AS 2.1 – 3 GB is available for the application.

For other operating systems, please refer to the OS documentation for your configuration.

Difference between process address space and physical memory

Each process gets its own address space. In 32 bit operating systems, this address space will range from 0 to 4 GB. This is independent of the available RAM or swap space in the machine. The total physical memory available on the machine is the sum of RAM and the swap space available on that machine. All the running processes share this physical memory.

The memory address within a process is virtual. The kernel maps this virtual address to the physical address. The physical address points to a location somewhere in the physical memory. At any given time, the sum of all the virtual memory used by the running processes in a machine cannot exceed the total physical memory available on that machine.

Why does the OOM problem occur and What does the JVM do in this situation?

Out of memory in java heap

The JVM throws java out of memory (java OOM) error if it is not able get more memory in java heap to allocate more java objects. The JVM cannot allocate more java objects if the java heap is full of live objects and it is not able to expand the java heap anymore.

In this situation, the JVM lets the application decide on what to do after throwing the java.lang.OutOfMemoryError?. For example, the application may handle this error and decide to shut down itself in a safe way or decide to run ignoring this error. If the application doesn’t handle this error, then the thread that throws this error will exit (you will not see this thread if you take a java thread dump).

Out of memory in native heap

The JVM throws native out of memory (native OOM) if it is not able to get any more native memory. This usually happens when the process reaches the process size limitation on that OS or the machine runs out of RAM and swap space.

When this happens, the JVM handles the native OOM condition, logs a message saying that it ran out of native memory or unable to acquire memory and exits. If the JVM or any other loaded module (like libc or a third party module) doesn’t handle this native OOM situation, then the OS will send a sigabort signal to the JVM which will make the JVM exit. Usually, the JVMs will generate a core file when it gets a sigabort signal.

Steps to debug the problem

Determine whether it is a Java OOM or Native OOM:

  • If the stdout/stderr/server log message says that this is a java.lang.OutOfMemoryError?, then this is Java OOM
  • If the stdout/stderr message says that it failed to acquire memory, then this is a Native OOM

For Java OOM

Reproduce the OOM

OOM almost always need a very long time to reproduce. Firstly we need find a as simple as possible way to reproduce it. The best one is to reproduce the OOM when run one case repeating.

Whatever, simple and less time is the key. This can also narrow down the bug.

Things can be checked in component

The application might be leaking some java memory constantly, which may cause this problem. Or, the application uses more live objects and it needs more java heap memory. The following things can be checked in the application:

  • Caching in the application - If the application caches java objects in memory, then we should make sure that this cache is not growing constantly. There should be a limit for the number of objects in the cache. We can try reducing this limit to see if it reduces the java heap usage.
  • Long living objects - If there are long living objects in the application, then we can try reducing the life of the objects if possible. For example, tuning HTTP session timeout will help in reclaiming the idle session objects faster.
  • Memory leaks – One example of memory leak is when using database connection pools in application server. When using connection pools, the JDBC statement and resultset objects must be explicitly closed in a finally block. This is due to the fact that calling close() on the connection objects from pool will simply return the connection back to the pool for re-use and it doesn’t actually close the connection and the associated statement/resultset objects.
  • Increase the java heap - We can also try increasing the java heap if possible to see whether that solves the problem.

If none of the above suggestion is applicable

Then we need to use a JVMPI (JVM Profiler Interface) based profiler like OptimizeIt? or Jprob to find out which objects are occupying the java heap.

JVM issues

This can not occur almost. Anyway, before throwing a java OOM JVM should do full GC and full compaction. If the GC cycle or compaction do not happen , then this is a JVM bug.

For Native OOM

Memory availability in the machine

If the machine doesn’t have enough RAM and swap space, then the OS will not be able to give more memory to this process that could also result in out of memory. Make sure that the sum of RAM and swap space in the disk is sufficient to cater to all the running processes in that machine.

Tuning java heap

If the java heap usage is well within the max heap, then reducing the java max heap will give more native memory to the JVM. This is not a solution but a workaround that can be tried. Since the OS limits the process size, we need to strike a balance between the java heap and the native heap.

Native memory usage by the JVM

The amount of native memory usage by the JVM is expected to flatten out after all the classes are loaded and the methods have been called (code generation is over). This usually happens within the first few hours for most of the applications. After that, the JVM uses only little native memory that may be due to run time class loading, code generation due to optimization etc.

In order to narrow down the problem, try disabling run time optimizations and check whether that makes any difference.

o In case of Jrockit, -Xnoopt flag can be used to disable run time optimizations.

o In case of SUN hotspot JVM, -Xint flag will force the JVM to run in interpreted mode (no code generation).

If the native memory usage continues to grow constantly throughout the run, then this could be a memory leak in the native code.

Third party native modules or JNI code in the application

Check whether you are using any third party native module like database drivers. These native modules could also allocate native memory and the leak may be from these modules. In order to narrow down the problem, you should attempt to reproduce the problem without these third party modules. For example, you can use pure java drivers instead of native database drivers.

Check whether your application uses some JNI code. This could also be causing native memory leak and you can try to run the application without the JNI code if possible.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值