Java:为什么它使用固定数量的内存?或者它如何管理记忆? [英] Java: why does it uses a fixed amount of memory? or how does it manage the memory?

查看:114
本文介绍了Java:为什么它使用固定数量的内存?或者它如何管理记忆?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

似乎JVM使用了一些固定数量的内存。至少我经常看到参数 -Xmx (对于最大尺寸)和 -Xms (对于初始尺寸)这表明。

It seems that the JVM uses some fixed amount of memory. At least I have often seen parameters -Xmx (for the maximum size) and -Xms (for the initial size) which suggest that.

我觉得Java应用程序不能很好地处理内存。我注意到的一些事情:

I got the feeling that Java applications don't handle memory very well. Some things I have noticed:


  • 即使是一些非常小的示例演示应用程序也会加载大量内存。也许这是因为加载了Java库。但为什么需要为每个Java实例加载库? (这似乎是因为多个小型应用程序线性占用更多内存。请参阅此处对于我描述这个问题的一些细节。)或者为什么这样做?

  • Even some very small sample demo applications load huge amounts of memory. Maybe this is because of the Java library which is loaded. But why is it needed to load the library for each Java instance? (It seems that way because multiple small applications linearly take more memory. See here for some details where I describe this problem.) Or why is it done that way?

像Eclipse这样的大型Java应用程序经常会遇到一些OutOfMemory异常。这总是很奇怪,因为我的系统上仍然有足够的内存。通常,它们会在运行时消耗越来越多的内存。我不确定他们是否有一些内存泄漏,或者这是因为内存池中的碎片 - 我觉得后者就是这种情况。

Big Java applications like Eclipse often crash with some OutOfMemory exception. This was always strange because there was still plenty of memory available on my system. Often, they consume more and more memory over runtime. I'm not sure if they have some memory leaks or if this is because of fragmentation in the memory pool -- I got the feeling that the latter is the case.

Java库似乎需要比Qt等类似功能强大的库更多的内存。为什么是这样? (比较,启动一些Qt应用程序并查看它们的内存使用情况并启动一些Java应用程序。)

The Java library seem to require much more memory than similar powerful libraries like Qt for example. Why is this? (To compare, start some Qt applications and look at their memory usage and start some Java apps.)

为什么没有它只使用基础系统技术,如 malloc 免费?或者,如果他们不喜欢libc实现,他们可以使用 jemalloc (例如在FreeBSD和 Firefox )这看起来很不错。我很确定这会比JVM内存池表现更好。而且不仅表现更好,还需要更少的内存,尤其是对于小型应用程序。

Why doesn't it use just the underlying system technics like malloc and free? Or if they don't like the libc implementation, they could use jemalloc (like in FreeBSD and Firefox) which seems to be quite good. I am quite sure that this would perform better than the JVM memory pool. And not only perform better, also require less memory, esp. for small applications.

增加:有人已经尝试过吗?我会对基于LLVM的Java JIT编译器感兴趣,它只使用 malloc / free 进行内存处理。

Addition: Does somebody have tried that already? I would be much interested in a LLVM based JIT-compiler for Java which just uses malloc/free for memory handling.

或者这也可能与JVM实现有所不同?我主要使用的是Sun JVM。

Or maybe this also differs from JVM implementation to implementation? I have used mostly the Sun JVM.

(另请注意:我不是在这里直接谈论GC .GC只负责计算可删除的对象并初始化内存释放但实际释放是一个不同的子系统.Afaik,它是一些自己的内存池实现,而不仅仅是对 free 的调用。)

(Also note: I'm not directly speaking about the GC here. The GC is only responsible to calculate what objects can be deleted and to initialize the memory freeing but the actual freeing is a different subsystem. Afaik, it is some own memory pool implementation, not just a call to free.)

编辑:一个非常相关的问题:为什么(Sun)JVM有一个固定的内存使用上限?或换句话说不一样:为什么JVM处理内存分配的方式与本机应用程序不同?

A very related question: Why does the (Sun) JVM have a fixed upper limit for memory usage? Or to put it differently: Why does JVM handle memory allocations differently than native applications?

推荐答案

您需要记住垃圾收集器做了很多事情不只是收集无法到达的对象。它还优化了堆空间并跟踪 完全其中有可用的内存来分配用于创建新对象。

You need to keep in mind that the Garbage Collector does a lot more than just collecting unreachable objects. It also optimizes the heap space and keeps track of exactly where there is memory available to allocate for the creation of new objects.

立即知道有空闲内存的位置可以将新对象分配到年轻代中,并防止需要来回运行底层操作系统。根据Sun的Jon Masamitsu,JIT编译器还优化了远离JVM层的分配:

Knowing immediately where there is free memory makes the allocation of new objects into the young generation efficient, and prevents the need to run back and forth to the underlying OS. The JIT compiler also optimizes such allocations away from the JVM layer, according to Sun's Jon Masamitsu:


快速路径分配不会调用
进入JVM来分配一个对象。
JIT编译器知道如何从年轻代中分配
,并且代码
用于对象分配的内联
生成分配。解释器
也知道如何在不调用VM的情况下进行
的分配。

Fast-path allocation does not call into the JVM to allocate an object. The JIT compilers know how to allocate out of the young generation and code for an allocation is generated in-line for object allocation. The interpreter also knows how to do the allocation without making a call to the VM.

注意JVM竭尽全力尝试获得大型连续内存块,这些内存块可能有他们自己的性能优势(参见丢失缓存的成本)。我想对 malloc (或其他选择)的调用在通话中提供连续内存的可能性有限,但也许我错过了那些。

Note that the JVM goes to great lengths to try to get large contiguous memory blocks as well, which likely have their own performance benefits (See "The Cost of Missing the Cache"). I imagine calls to malloc (or the alternatives) have a limited likelihood of providing contiguous memory across calls, but maybe I missed something there.

此外,通过维护内存本身,垃圾收集器可以根据使用情况和访问模式进行分配优化。现在,我不知道它在多大程度上做到这一点,但鉴于已经注册了Sun 这个概念,我想他们已经用它做了一些事情。

Additionally, by maintaining the memory itself, the Garbage Collector can make allocation optimizations based on usage and access patterns. Now, I have no idea to what extent it does this, but given that there's a registered Sun patent for this concept, I imagine they've done something with it.

保持这些内存块的分配也为Java程序提供了保障。由于垃圾收集对程序员是隐藏的,所以他们无法告诉JVM不,保留那些内存;我已经完成了这些对象,但我需要新的空间。通过保留内存,GC不会有放弃内存的风险,它将无法返回。当然,你总是可以得到一个 OutOfMemoryException ,但是每次你完成一个对象时,不必毫不费力地将内存返回给操作系统似乎更合理。你已经为自己找到了麻烦。

Keeping these memory blocks allocated also provides a safeguard for the Java program. Since the garbage collection is hidden from the programmer, they can't tell the JVM "No, keep that memory; I'm done with these objects, but I'll need the space for new ones." By keeping the memory, the GC doesn't risk giving up memory it won't be able to get back. Naturally, you can always get an OutOfMemoryException either way, but it seems more reasonable not to needlessly give memory back to the operating system every time you're done with an object, since you already went to the trouble to get it for yourself.

除此之外,我会尝试直接解决你的一些评论:

All of that aside, I'll try to directly address a few of your comments:


通常,它们会在运行时消耗越来越多的
内存。

Often, they consume more and more memory over runtime.

假设这不仅仅是程序正在做什么(无论出于何种原因,也许它有泄漏,也许它必须跟踪越来越多的数据),我想它与它有关(Sun / Oracle)JVM设置的免费哈希空间比率默认值。 -XX:MinHeapFreeRatio 的默认值为40%,而 -XX:MaxHeapFreeRatio 为70%。这意味着只要剩余40%的堆空间,就会通过从操作系统声明更多内存来调整堆的大小(假设这不会超过 -Xmx )。相反,如果可用空间超过70%,它只会将堆内存释放回操作系统。

Assuming that this isn't just what the program is doing (for whatever reason, maybe it has a leak, maybe it has to keep track of an increasing amount of data), I imagine that it has to do with the free hash space ratio defaults set by the (Sun/Oracle) JVM. The default value for -XX:MinHeapFreeRatio is 40%, while -XX:MaxHeapFreeRatio is 70%. This means that any time there is only 40% of the heap space remaining, the heap will be resized by claiming more memory from the operating system (provided that this won't exceed -Xmx). Conversely, it will only* free heap memory back to the operating system if the free space exceeds 70%.

考虑如果我在Eclipse中运行内存密集型操作会发生什么;例如,分析。我的内存消耗将会上升,并在整个过程中调整堆大小(可能是多次)。一旦我完成了,内存需求就会下降,但是到目前为止,70%的堆都是免费的。这意味着现在分配了大量未充分利用的空间,JVM无意释放。这是一个主要缺点,但您可以通过自定义您的情况的百分比来解决它。为了更好地了解这一点,您应该对应用程序进行概要分析,以便查看已使用和已分配的堆空间。我个人使用 YourKit ,但有很多好的选择可供选择。

Consider what happens if I run a memory-intensive operation in Eclipse; profiling, for example. My memory consumption will shoot up, resizing the heap (likely multiple times) along the way. Once I'm done, the memory requirement falls back down, but it likely won't drop so far that 70% of the heap is free. That means that there's now a lot of underutilized space allocated that the JVM has no intention of releasing. This is a major drawback, but you might be able to work around it by customizing the percentages to your situation. To get a better picture of this, you really should profile your application so you can see the utilized versus allocated heap space. I personally use YourKit, but there are many good alternatives to choose from.

*我不知道这是否实际上是唯一的时间以及如何从操作系统的角度观察到这一点,但文档说明这是最大百分比 GC后的堆免费避免收缩,这似乎表明了这一点。

*I don't know if this is actually the only time and how this is observed from the perspective of the OS, but the documentation says it's the "maximum percentage of heap free after GC to avoid shrinking," which seems to suggest that.


Even一些非常小的示例演示
应用程序加载了大量的
内存。

Even some very small sample demo applications load huge amounts of memory.

我想这取决于什么样的他们的应用程序。我觉得Java GUI应用程序运行内存很重,但我没有任何证据。你有一个我们可以看到的具体例子吗?

I guess this depends on what kind of applications they are. I feel that Java GUI applications run memory-heavy, but I don't have any evidence one way or another. Did you have a specific example that we could look at?


但为什么需要为每个Java加载
库实例?

But why is it needed to load the library for each Java instance?

那么,如果不创建新的JVM进程,您将如何处理加载多个Java应用程序?过程的隔离是一件好事,这意味着独立加载。不过,我认为这对于一般的流程来说并不常见。

Well, how would you handle loading multiple Java applications if not creating new JVM processes? The isolation of the processes is a good thing, which means independent loading. I don't think that's so uncommon for processes in general, though.

作为最后一点,你在另一个问题中提到的缓慢启动时间可能来自几个初始阶段达到基线应用程序内存要求所需的堆重新分配(由于 -Xms -XX:MinHeapFreeRatio ),具体取决于JVM的默认值是什么。

As a final note, the slow start times you asked about in another question likely come from several intial heap reallocations necessary to get to the baseline application memory requirement (due to -Xms and -XX:MinHeapFreeRatio), depending what the default values are with your JVM.

这篇关于Java:为什么它使用固定数量的内存?或者它如何管理记忆?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆