【问题标题】:Java Out of Memory Error(Native memory), the process size limit was hit(32-bit linux)Java Out of Memory Error(Native memory),进程大小限制被命中(32位linux)
【发布时间】:2013-09-08 23:03:57
【问题描述】:

我正在测试 Web 应用程序的性能,并且出现“内存不足错误”(本机内存)。

我测试了好几次,每次都“为 Chunk::new 分配 83886088 字节失败”而死。

我每分钟打印一次内存大小,发现进程死亡前的VmSize是2924700 kB。

我认为已达到进程大小限制。我把 -Xmx2000m 改成 -Xmx1900m 就可以了。

一些问题:

1.如何确认已达到进程大小限制。不完全是 3G 内存。

2.为什么JVM每次都分配83886088字节的内存?从异常栈看,似乎和GC的事情有关。

3.JVM除了堆内存(-Xmx)和非堆内存(-XX:MaxPermSize)外,还应该保留多少内存?以及如何知道它现在使用了多少?

感谢并为我糟糕的英语感到抱歉。

Linux 2.6.16.60-0.83.2-bigsmp JRE 6.0_25-b06 雄猫 7.0.37

jvm options: -Xms2000m -Xmx2000m -XX:PermSize=256M -XX:MaxPermSize=512m -XX:+UseConcMarkSweepGC -XX:+UseParNewGC

/proc/meminfo:
MemTotal:     24935548 kB
MemFree:      13564968 kB

# Native memory allocation (malloc) failed to allocate 83886088 bytes for Chunk::new
# Possible reasons:
#   The system is out of physical RAM or swap space
#   In 32 bit mode, the process size limit was hit
...
# This output file may be truncated or incomplete.
#
#  Out of Memory Error (allocation.cpp:317), pid=18217, tid=275671968

---------------  T H R E A D  ---------------

Current thread (0x105a1c00):  VMThread [stack: 0x10666000,0x106e7000] [id=18243]

Stack: [0x10666000,0x106e7000],  sp=0x106e5ae0,  free space=510k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [libjvm.so+0x724710]  VMError::report_and_die()+0x2b0
V  [libjvm.so+0x2f68ef]  report_vm_out_of_memory(char const*, int, unsigned, char const*)+0x4f
V  [libjvm.so+0x1576fc]  Chunk::operator new(unsigned, unsigned)+0x5c
V  [libjvm.so+0x157c26]  Arena::grow(unsigned)+0x26
V  [libjvm.so+0x6457e9]  resource_allocate_bytes(unsigned)+0x49
V  [libjvm.so+0x3a03ef]  GenericGrowableArray::raw_allocate(int)+0xbf
V  [libjvm.so+0x3402ee]  GrowableArray<oopDesc*>::grow(int)+0x3e
V  [libjvm.so+0x3a62b1]  FindInstanceClosure::do_object(oopDesc*)+0x51
V  [libjvm.so+0x2ae571]  CompactibleFreeListSpace::object_iterate(ObjectClosure*)+0x51
V  [libjvm.so+0x38d066]  GenerationObjIterateClosure::do_space(Space*)+0x16
V  [libjvm.so+0x2d6498]  ConcurrentMarkSweepGeneration::space_iterate(SpaceClosure*, bool)+0x18
V  [libjvm.so+0x38be22]  Generation::object_iterate(ObjectClosure*)+0x22
V  [libjvm.so+0x2d9f9d]  ConcurrentMarkSweepGeneration::object_iterate(ObjectClosure*)+0x4d
V  [libjvm.so+0x37fd65]  GenCollectedHeap::object_iterate(ObjectClosure*)+0x55
V  [libjvm.so+0x3a61fe]  HeapInspection::find_instances_at_safepoint(klassOopDesc*, GrowableArray<oopDesc*>*)+0x3e
V  [libjvm.so+0x6eca91]  ConcurrentLocksDump::dump_at_safepoint()+0xf1
V  [libjvm.so+0x6e7561]  Threads::print_on(outputStream*, bool, bool, bool)+0x201
V  [libjvm.so+0x734927]  VM_PrintThreads::doit()+0x27
V  [libjvm.so+0x734576]  VM_Operation::evaluate()+0x46
V  [libjvm.so+0x733a23]  VMThread::evaluate_operation(VM_Operation*)+0x83
V  [libjvm.so+0x733c90]  VMThread::loop()+0x190
V  [libjvm.so+0x733780]  VMThread::run()+0x80
V  [libjvm.so+0x5e294e]  java_start(Thread*)+0x14e
C  [libpthread.so.0+0x54ab]  short+0x8b

VM_Operation (0x0caff000): PrintThreads, mode: safepoint, requested by thread 0x09ec3800


---------------  P R O C E S S  ---------------

Java Threads: ( => current thread )
...//209 Java Threads

Heap
 par new generation   total 147456K, used 126550K [0x161f0000, 0x201f0000, 0x201f0000)
  eden space 131072K,  92% used [0x161f0000, 0x1d869d18, 0x1e1f0000)
  from space 16384K,  31% used [0x1e1f0000, 0x1e70be78, 0x1f1f0000)
  to   space 16384K,   0% used [0x1f1f0000, 0x1f1f0000, 0x201f0000)
 concurrent mark-sweep generation total 1884160K, used 1697819K [0x201f0000, 0x931f0000, 0x931f0000)
 concurrent-mark-sweep perm gen total 262144K, used 61769K [0x931f0000, 0xa31f0000, 0xb31f0000)

Code Cache  [0xb391f000, 0xb44b7000, 0xb691f000)
 total_blobs=3924 nmethods=3719 adapters=157 free_code_cache=38272704 largest_free_block=9600

【问题讨论】:

  • 你为什么要使用 32 位?如果你不能使用 64 位,我至少会使用 Java 6 update 45 而不是 update 25。
  • 还有其他程序,替换它们需要花费很多时间。

标签: java linux memory


【解决方案1】:

每分钟打印一次内存大小,发现进程死亡前VmSize为2924700 kB。

AFAIK 在 Linux 上,操作系统使用大约 1 GB。您需要用于线程堆栈、共享库、Perm Gen、内存映射文件和任何本机资源的虚拟内存。

如果您接近这个限制(或者如果您只有 64 位处理器),那么您确实应该使用 64 位操作系统和 JVM。如果不是 Java 7 update 25,我会使用 Java 6 update 45,即免费支持的结束。

【讨论】:

    【解决方案2】:

    进程大小限制

    现代 Linux 操作系统在 32 位版本中可以使用超过 4GB 的 RAM,方法是使用名为 Physical Address Extension (PAE) 的东西。

    但如果你什么都不做,3GB 似乎是进程可能达到的合理限制。

    也就是说,这与您的情况完全无关。错误不是来自内核(您没有得到核心转储),而是来自 Java 运行时。

    在 GC 中发生这种情况的原因是其他一些线程要求另外 83886088 字节的空闲内存并且没有剩余。因此,VM 启动了 GC 以腾出空间。不幸的是,所有对象仍在使用中 -> 内存不足错误。

    为什么JVM每次都分配83886088字节的内存?

    软件应该是确定性的,即每次运行时它都应该产生相同的结果。

    看看其他线程。其中一个只是试图准确分配这块内存。

    除了堆内存(-Xmx)和非堆内存(-XX:MaxPermSize)之外,应该为JVM保留多少内存?

    这取决于您的应用程序做什么。但通常情况下,内存不足意味着您有内存泄漏(即某些东西保留了它不再需要的大对象)。

    使用像 MATYourKit 这样的分析器来确定可能是什么。

    以及如何知道它现在使用了多少?

    使用jconsoleVisualVM 监控内存使用情况。

    相关:

    【讨论】:

    • 1. PAE 意味着操作系统可以使用所有内存来运行进程;单个进程仍被限制在 3GB 大小限制内。 2. JVM 通常具有良好的错误处理能力,因此当它们耗尽内存时,它们会输出一个与此处完全相同的冗长错误,而不仅仅是核心转储。
    • @Joni:没错,但是我给 Java 2GB 并且内核只剩下 1GB 会发生什么?我认为内核会在打印 OOM 之前杀死 Java。
    • 从输出中可以看到机器有大量未使用的内存(大约 13GB)。但总的来说,您是对的,在 Linux 上,OOM 杀手不会让程序有机会很好地退出。
    【解决方案3】:

    尝试更改线程的堆栈大小,使用 -Xss=N 标志(例如,-Xss=256k)。默认情况下,Linux 大小为 320 KB(在 64 位机器中大小为 1 MB)。通常,Out of Native Memory 发生的原因如下:

    请注意,在 1 和 2 的情况下更改堆栈大小会有所帮助。

    1. 在 32 位 JVM 中,进程最大为 4 GB(或更少,取决于操作系统) 大小。
    2. 系统实际上已经耗尽了虚拟内存。
    3. 在 Unix 风格的系统上,用户已经创建了(在她所在的所有程序之间) running) 为她的登录配置的最大进程数。个人 在这方面,线程被视为一个进程。

    希望这会有所帮助。

    问候, 皮纳基

    【讨论】:

      猜你喜欢
      • 2023-03-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多