Comparison of Java and C++: Difference between revisions

Content deleted Content added
m clean up spacing around commas and other punctuation, replaced: ,c → , c, ,e → , e, , → , , ; → ;
m Typo/general fixes, replaced: should never used → should never be used, ’s → 's
Line 316:
* Java and C++ use different idioms for resource management. Java relies mainly on garbage collection, which can reclaim memory,{{sfn|Bloch|2018|loc=Chapter §2 Item 8: Avoid finalizers and cleaners|pp=29-33}} while C++ relies mainly on the [[Resource Acquisition Is Initialization]] (RAII) idiom. This is reflected in several differences between the two languages:
** In C++ it is common to allocate objects of compound types as local stack-bound variables which are destroyed when they go out of scope. In Java compound types are always allocated on the heap and collected by the garbage collector (except in virtual machines that use [[escape analysis]] to convert heap allocations to stack allocations).
** C++ has destructors,{{sfn|Bloch|2018|loc=Chapter §2 Item 8: Avoid finalizers and cleaners|pp=29-33}} while Java has [[finalizer]]s.{{sfn|Bloch|2018|loc=Chapter §2 Item 8: Avoid finalizers and cleaners|pp=29-33}} Both are invoked before an object's deallocation, but they differ significantly. A C++ object's destructor must be invoked implicitly (in the case of stack-bound variables) or explicitly to deallocate an object. The destructor executes [[Synchronization|synchronously]] just before the point in a program at which an object is deallocated. Synchronous, coordinated uninitializing and deallocating in C++ thus satisfy the RAII idiom. Destructors in C++ is the normal way of getting back the resources associated with an object, and is a needed counterpart to constructors.{{sfn|Bloch|2018|loc=Chapter §2 Item 8: Avoid finalizers and cleaners|pp=29-33}} In Java, object deallocation is implicitly handled by the garbage collector. A Java object's finalizer is invoked [[Asynchrony (computer programming)|asynchronously]] some time after it has been accessed for the last time and before it is deallocated. Very few objects need finalizers. A finalizer is needed by only objects that must guarantee some cleanup of the object state before deallocating, typically releasing resources external to the JVM.{{sfn|Bloch|2018|loc=Chapter §2 Item 8: Avoid finalizers and cleaners|pp=29-33}} Direct usages of finalizers are usually not advised, as they are unpredictable, usually dangerous, and most of the time unneeded.{{sfn|Bloch|2018|loc=Chapter §2 Item 8: Avoid finalizers and cleaners|pp=29-33}} One has to be cautious not to think of finalizers as C++ destructors.{{sfn|Bloch|2018|loc=Chapter §2 Item 8: Avoid finalizers and cleaners|pp=29-33}} Rather, the try-with-resources or try-finally block achieves a more similar purpose as the destructor.{{sfn|Bloch|2018|loc=Chapter §2 Item 8: Avoid finalizers and cleaners|pp=29-33}} One problem with finalizers or cleaners is that it is not guaranteed that they will run immediately.{{sfn|Bloch|2018|loc=Chapter §2 Item 8: Avoid finalizers and cleaners|pp=29-33}} Hence, a finalizer should never be used for tasks that are time-critical.{{sfn|Bloch|2018|loc=Chapter §2 Item 8: Avoid finalizers and cleaners|pp=29-33}} Additionally, finalizers come with severe performance penalties and significantly increase the time it takes for objects to be deallocated, so their use is discouraged and deprecated in Java 9.
** With RAII in C++, one type of resource is typically wrapped inside a small class that allocates the resource upon construction and releases the resource upon destruction, and provide access to the resource in between those points. Any class that contain only such RAII objects do not need to define a destructor since the destructors of the RAII objects are called automatically as an object of this class is destroyed. In Java, safe synchronous deallocation of resources can be performed deterministically using the try/catch/finally construct. Alternatively, the try-with-resources construct, which was introduced in Java 7, should be used in preference to try-finally construct. {{sfn|Bloch|2018|loc=Chapter §2 Item 9: Prefer try-with-resources to try-finally|pp=34-36}} The try-with-resources construct is more concise and readable.{{sfn|Bloch|2018|loc=Chapter §2 Item 9: Prefer try-with-resources to try-finally|pp=34-36}} It also provide more helpful diagnostic information, since suppressed exception are not discarded, and will be printed in the stack trace with information saying that they were suppressed.{{sfn|Bloch|2018|loc=Chapter §2 Item 9: Prefer try-with-resources to try-finally|pp=34-36}}
** In C++, it is possible to have a [[dangling pointer]], a stale [[Reference (computer science)|reference]] to an object that has already been deallocated. Attempting to use a dangling pointer typically results in program failure. In Java, the garbage collector will not destroy a referenced object.
Line 430:
|title= Liquid SIMD: Abstracting SIMD hardware using lightweight dynamic mapping |journal= Hpca'07 |pages=216–227 |year= 2007}}</ref>
* The mandatory use of reference-semantics for all user-defined types in Java can introduce large amounts of superfluous memory indirections (or jumps) (unless elided by the JIT compiler) which can lead to frequent cache misses (a.k.a. [[Thrashing (computer science)|cache thrashing]]). Furthermore, cache-optimization, usually via cache-aware or [[Cache-oblivious algorithm|cache-oblivious]] data structures and algorithms, can often lead to orders of magnitude improvements in performance as well as avoiding time-complexity degeneracy that is characteristic of many cache-pessimizing algorithms, and is therefore one of the most important forms of optimization; reference-semantics, as mandated in Java, makes such optimizations impossible to realize in practice (by neither the programmer nor the JIT compiler).
* [[garbage collection (computer science)|Garbage collection]],<ref name="hundt2011">{{cite web| last=Hundt |first=Robert |title=Loop Recognition in C++/Java/Go/Scala |publisher=[[Scala Days]] 2011 |date=2011-04-27|___location=Stanford, California |access-date=2012-11-17 |url=https://days2011.scala-lang.org/sites/days2011/files/ws3-1-Hundt.pdf |archive-url=https://ghostarchive.org/archive/20221009/https://days2011.scala-lang.org/sites/days2011/files/ws3-1-Hundt.pdf |archive-date=2022-10-09 |url-status=live |quote=Java shows a large GC component, but a good code performance. [...] We find that in regards to performance, C++ wins out by a large margin. [...] The Java version was probably the simplest to implement, but the hardest to analyze for performance. Specifically the effects around garbage collection were complicated and very hard to tune; 318&nbsp;kB}}</ref> as this form of automatic memory management introduces memory overhead.<ref name="HertzBerger2005">{{cite web |url=http://people.cs.umass.edu/~emery/pubs/gcvsmalloc.pdf |title=Quantifying the Performance of Garbage Collection vs. Explicit Memory Management |author=Matthew Hertz, Emery D. Berger |publisher=OOPSLA 2005 |date=2005 |access-date=2015-03-15 |quote=In particular, when garbage collection has five times as much memory as required, its runtime performance matches or slightly exceeds that of explicit memory management. However, garbage collection’scollection's performance degrades substantially when it must use smaller heaps. With three times as much memory, it runs 17% slower on average, and with twice as much memory, it runs 70% slower. |archive-url=https://web.archive.org/web/20170706100244/https://people.cs.umass.edu/~emery/pubs/gcvsmalloc.pdf |archive-date=6 July 2017 |url-status=dead }}</ref>
 
However, there are a number of benefits to Java's design, some realized, some only theorized: