for example the original specification for the C# language referred to "destructors", even though C# is garbage-collected, but the specification for the Common Language Infrastructure (CLI), and the implementation of its runtime environment as the Common Language Runtime (CLR), referred to "finalizers". This is reflected in the C# language committee's notes, which read in part: "The C# compiler compiles destructors to ... [probably] instance finalizer[s]". This terminology is confusing, and thus more recent versions of the C# spec refer to the language-level method as "finalizers". Another language that does not make this terminology distinction is D. Although D classes are garbage collected, their cleanup functions are called destructors. Use Finalization is mostly used for cleanup, to release memory or other resources: to deallocate memory allocated via manual memory management; to clear references if reference counting is used (decrement reference counts); to release resources, particularly in the Resource Acquisition Is Initialization (RAII) idiom; or to unregister an object. The amount of finalization varies significantly between languages, from extensive finalization in C++, which has manual memory management, reference counting, and deterministic object lifetimes; to often no finalization in Java, which has non-deterministic object lifetimes and is often implemented with a tracing garbage collector. It is also possible for there to be little or no explicit (user-specified) finalization, but significant implicit finalization, performed by the compiler, interpreter, or runtime; this is common in case of automatic reference counting, as in the CPython reference implementation of Python, or in Automatic Reference Counting in Apple's implementation of Objective-C, which both automatically break references during finalization. A finalizer can include arbitrary code; a particularly complex use is to automatically return the object to an object pool. Memory deallocation during finalization is common in languages like C++ where manual memory management is standard, but also occurs in managed languages when memory has been allocated outside of the managed heap (externally to the language); in Java this occurs with Java Native Interface (JNI) and ByteBuffer objects in New I/O (NIO). This latter can cause problems due to the garbage collector being unable to track these external resources, so they will not be collected aggressively enough, and can cause out-of-memory errors due to exhausting unmanaged memory – this can be avoided by treating native memory as a resource and using the dispose pattern, as discussed below. Finalizers are generally both much less necessary and much less used than destructors.