Java、JIT 和垃圾收集器效率
我想了解一下Java的效率以及Java虚拟机和Android的优缺点。 效率是指内存使用率低、处理器使用率低以及执行速度快。
移动设备比 PC 更简单,因此应用程序需要更高效。服务器接收许多连接,并且它们需要非常高效。许多移动设备使用 Android 和 Java 应用程序,许多服务器使用 PHP。
Java 和解释性语言(例如 Java Script、Python 和 PHP)能否比 C 和 C++ 更高效?
JIT(即时)优点:
- 它可以更好地优化,因为它知道一些变量的值以及它在哪里使用或更改。
- 它了解处理器并可以使用处理器特定指令进行优化。
- 将函数转换为内联函数更容易。
- 它可以删除已知的条件测试并删除不会运行的块。
Java的缺点:
- 当应用程序第一次运行时,应用程序会非常慢,因为字节码将被解释并且JIT编译器将进行许多分析以找到良好的优化。应用程序无法使用最大硬件功率。如果一个应用程序是游戏或实时应用程序,如果它第一次成功运行并且没有延迟,但它使用了最大的硬件功率,那么下次运行该应用程序时,它将不会使用通过优化,最大限度地发挥硬件能力。问题是应用程序无法设计为优化后使用最大的硬件功率,因为它在第一次运行时会太慢,并且不会继续运行。
- Java 检查数组索引是否越界,并检查指针是否不为空。它将在生成的代码中添加几个内部“if”。
- 所有对象都使用垃圾收集器,包括非常容易手动删除的对象。
- 所有对象实例都是通过动态内存分配创建的,包括可以轻松使用堆栈的对象。如果循环迭代开始创建类的实例并结束删除创建的对象,则动态内存分配将效率低下。
- 垃圾收集器在清理内存时需要停止应用程序,这对于游戏、GUI 应用程序和实时应用程序来说是非常不受欢迎的。引用计数很慢并且无法处理循环引用。多线程垃圾收集器速度较慢,并且需要更多的 CPU 使用。
I want to know about the efficiency of Java and the advantages and disadvantages of Java Virtual Machine and Android.
Efficiency is the low use of memory, low use of the processor and fast execution.
Mobile devices are simpler than PC, then the apps need to be more efficient. Servers receive many connections and they need to be very efficient. Many mobile devices use Android and Java apps, and many servers use PHP.
Can Java and interpreted languages, such as Java Script, Python and PHP, be more efficient than C and C++?
JIT (just in time) advantages:
- It can optimize better, because it knows the value of some variables and where it is used or changed.
- It knows the processor and can optimize with processor specific instructions.
- It is easier to transform functions into inline function.
- It can remove known conditional tests and remove blocks that will not be run.
Java disadvantages:
- When the app run for the first time, the app will be very slow, because the bytecodes will be interpreted and JIT compiler will do many analysis to find good optimizations. The apps cannot use the maximum of the hardware power. If an app is a game or a real-time app, if it be run for the first successfully and with no delay, but it uses the maximum of the hardware power, then the next time the app be run, it will not use the maximum of the hardware power due to optimizations. The problem is the app cannot be designed to use the maximum of the hardware power after the optimization, because it will be too slow on the first run, and will not continue to run.
- Java checks if the array index is not out of bounds, and it checks if the pointers are not null. It will add several internal "if"s to generated code.
- All objects use garbage collector, including objects that are very easy to manually delete.
- All instances of objects are created with dynamic memory allocation, including objects that can easily use the stack. If a loop iteration begins creating an instance of a class and ends deleting the created object, dynamic memory allocation will be inefficient.
- The garbage collector needs to stop the app while it cleans the memory and it is very undesired for games, GUI apps and real-time apps. Reference counting is slow and it cannot handle circular references. Multi-threaded garbage collector is slower and it needs more use of the CPU.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
很难比最好的 C 和 C++ 程序更高效。不过,有很多 C 和 C++ 程序的效率远没有那么高,如果您足够优秀,用(现代)Java 代码击败它们是非常实用的。
我也听说过有关当前同类最佳 Javascript 引擎的好消息,但我从未详细研究过它们。
对于 Python 和 PHP(以及许多其他语言)来说,情况有点不同。这些语言是用 C 编写的,因此很明显它们不可能比 C 更高效(遵循构造)。然而,在其中编写高效的代码(即,使用实际上编写得非常好的 C 库)比从头开始要容易得多。特别是,它减少了每个程序的缺陷数量。这在实践中是一个非常重要的指标;如果允许错误,任何人都可以编写快速代码。
一般来说,我建议不要担心获得最大效率。你遇到了收益递减法则。相反,使用明智的整体算法(或者,正如我的一个朋友曾经对我说的那样,“照顾大 O(),让常数因素照顾自己”)并关注程序是否足够好的问题在实践中。一旦完成,就别再折腾了,赶紧发货吧!
It's very difficult to get more efficient than the best C and C++ programs. There's a lot of C and C++ programs that are nowhere near as efficient as that though, and beating them with (modern) Java code is quite practical if you're any good.
I've also heard good things about the current best-of-breed Javascript engines, but I've never studied them in detail.
With Python and PHP (and many other languages besides) it's a bit different. Those languages are written in C, so it's obvious they cannot be more efficient than C (follows by construction). Yet it's much easier to write efficient code in them (i.e., that uses what is in-effect a very well-written C library) than it is to start from scratch. In particular, it reduces the number of defects per program. That's a very important metric in practice; anyone can produce fast code if it's allowed to be wrong.
In general, I advise not worrying about getting maximal efficiency. You run up against the law of diminishing returns. Instead, use sensible overall algorithms (or, as a friend of mine once said to me, “look after the big O()s and let the constant factors look after themselves”) and focus on the question of whether the program is good enough in practice. Once it is, stop fiddling around and ship it!
让我们来分析一下您声称的缺点:
JIT编译是一个实现问题。并非所有平台都这样做。事实上,Android 平台可以修改为 1) 提前编译,或 2) 缓存 JIT 生成的本机代码,以便下次运行应用程序时启动速度更快。
有趣的是,不同的 Java 供应商在不同的时间尝试过这些策略,但经验证据表明,普通的 JIT 是最好的策略。
JIT 编译器可以优化掉许多这样的测试。对于其他人来说,管理费用往往相对较小;例如百分之几的差异...不是 2 的因数。
请注意,检查的替代方法是典型应用程序错误将使 Android 平台崩溃的风险。当然,如果应用程序可以丢弃内存,垃圾收集就会出现问题。
另一方面是很容易忘记删除对象、删除对象两次、删除后使用它们等等。这些错误都会导致难以追踪的错误。
Java 动态内存分配和对象创建速度很快。例如,比 C++ 更快。
然后使用并发/低暂停垃圾收集器。另一种方法是实现您的应用程序不生成大量垃圾......并且很少触发垃圾收集。
没有像样的 Java GC 使用引用计数。 (另一方面,很多 C/C++ 手动内存管理方案都是这样做的。例如,C++ 中所谓的智能指针方案。)
我认为你实际上是指并发收集。是的,确实如此,但这是您为交互式游戏/实时应用程序所需的额外响应能力付出的代价。
Let's pick apart your claimed disadvantages:
JIT compilation is an implementation issue. Not all platforms do it. Indeed, the Android platform could be modified to 1) do ahead of time compilation, or 2) cache the native code produced by the JIT to give faster startup next time you run the app.
It is interesting that various Java vendors have tried these strategies at various times, and yet the empirical evidence is that plain JIT is the best strategy.
The JIT compiler can optimize away many of these tests. For the rest, the overheads tend to be relatively small; e.g. a few percent difference ... not a factor of 2.
Note that the alternative to checking is the risk that typical application bugs will crash the android platform. Certainly, garbage collection becomes problematic if applications can trash memory.
The flip-side is that it is easy to forget to delete objects, delete objects twice, use them after they have been deleted and so on. These mistakes all lead to bugs that tend to be hard to track down.
Java dynamic memory allocation and object creation is FAST. Faster than in C++ for example.
Use a concurrent / low-pause garbage collector then. Another approach is to implement your app to not generate lots of garbage ... and seldom trigger garbage collection.
No decent Java GC uses reference counting. (On the other hand, a lot of C / C++ manual memory management schemes do. For instance, so-called smart pointer schemes in C++.)
You actually mean concurrent collection I think. Yes it does, but that's the penalty you pay for the extra responsiveness that you demand for interactive games / realtime apps.
你所描述的“高效”我会描述为“理想”。换句话说,一个需要很少内存、很少 CPU 时间并且运行速度很快的应用程序,就是一个同时又好、快又便宜的应用程序。不要介意它是否有任何有用或有趣的东西。
如果需要所有三个目标,我认为唯一合理的比较是在产生共同结果的应用程序之间进行比较。在这种情况下,考虑到一群能力相当的程序员相互竞争,任何一种实现都不太可能在所有这三个方面都优于其他实现。
也就是说,您的问题遗漏了移动市场的一个关键标准:应用程序开发速度。移动应用程序从积极的用户体验中获得的利润也远远高于后端优化。如果没有这种限制,你所说的效率问题在我看来更像是一个繁重的考虑,而不是一个实际的问题。
但对于实际问题:像 Java 这样的语言能否比静态编译到目标机器指令集的语言生成更高效的代码?可能不会。它能同样高效,或者足够高效吗?绝对地。如果我们考虑一个具有固定的、严格受限的资源且不经常变化的执行平台,那就是另一回事了。
What you describe as 'efficient' I would describe as 'ideal'. An application that requires little memory, little CPU time and runs quickly, put another way, is one that is good, fast, and cheap all at the same time. Never mind if it does anything useful or interesting.
The only comparison I'd view as reasonable, if all three goals are required, is among applications that produce a common result. In that case, it is unlikely, given a competing group of evenly-capable programmers, that any one implementation would excel on all three counts over the others.
That said, your question leaves out a key criterion to the mobile market: rate of application development. Mobile applications also profit far more from positive user experience than back-end optimization. Without that constraint, the question of efficiency as you put it, seems to me more of an ponderous consideration than a practical one.
But to the actual question: can a language like Java produce more efficient code than one that compiles statically to the instruction set of the target machine? Probably not. Can it be as efficient, or efficient enough? Absolutely. If we considered an execution platform with fixed, severely constrained resources that changes infrequently, it would be a different matter.
在任何语言中,获得快速执行的方法是用尽可能少的执行和尽可能少的垃圾收集来完成工作。
这听起来像是一个空洞的笼统,但在实践中,无论使用哪种语言,它的含义都是
对于数据结构设计,请使其尽可能简单。远离那些花哨的收藏课程。特别是远离通知作为保持数据一致性的一种方式。如果你的数据是标准化的,它就永远不会不一致。如果不能规范化,最好容忍暂时的不一致,而不是试图用通知来保持紧密。
即使是最好的代码,性能问题也会悄然出现。你应该尽量不做它们,但你仍然会做它们。最重要的是知道如何找到它们(一旦生成)并将其删除。 这是一个详细的示例。如果在做这样,您发现需要一种更好的大 O 算法,然后将其放入。在不确定是否需要的情况下放入一个算法会导致速度缓慢。
没有任何语言可以将程序从未消除的性能问题中拯救出来。该语言及其编译器、JITter 等就像一匹赛马。想要一匹好马固然很好,但如果骑师不是尽可能苗条那就太浪费了。
你的计划是骑师,你的工作就是让它参加减肥计划。
In any language, the way to get fast execution is to do the job with as little execution as possible, and as little garbage collection as possible.
That sounds like a vacuous generality, but what it means in practice, regardless of language, is
For the data structure design, keep it as simple as possible. Stay away from the fancy collection classes full of bells and whistles. Especially stay away from notifications as a way of keeping data consistent. If your data is normalized, it can never be inconsistent. If you can't normalize it, it's better to tolerate temporary inconsistency, than to try to keep it tight with notifications.
Performance problems creep in, even into the best code. You should try not to make them, but you will still make them. Most important is knowing how to find them, once made, and remove them. Here's a blow-by-blow example. If in doing this, you find you need a better big-O algorithm, then put it in. Putting one in without being sure it's needed is a recipe for slowness.
No language can rescue a program from non-removed performance problems. The language and its compiler, JITter, etc. are like a race horse. It's fine to want a good horse, but it's a waste if the jockey isn't as slim as possible.
Your program is the jockey, and it's your job to take it on a weight-loss program.
我将在编程大师。
I will paste an interesting answer given by the James Gosling himself in the Book Masterminds of Programming.