0% found this document useful (0 votes)
1 views18 pages

Bca Java Programming Unit-2

Garbage Collection in Java automates memory management, allowing developers to focus on coding without worrying about memory leaks and allocation. It involves processes like marking, sweeping, and compacting to reclaim memory from unused objects, and can be triggered by various events such as heap space allocation and explicit requests. Understanding garbage collection is crucial for optimizing application performance and preventing OutOfMemoryErrors.

Uploaded by

heded92396
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
1 views18 pages

Bca Java Programming Unit-2

Garbage Collection in Java automates memory management, allowing developers to focus on coding without worrying about memory leaks and allocation. It involves processes like marking, sweeping, and compacting to reclaim memory from unused objects, and can be triggered by various events such as heap space allocation and explicit requests. Understanding garbage collection is crucial for optimizing application performance and preventing OutOfMemoryErrors.

Uploaded by

heded92396
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 18

Garbage Collection

Garbage Collection is a key feature of the Java programming language that automatically manages memory
allocation and deallocation for objects that are created in an eden space.

Garbage Collection in Java allows developers to focus on writing code without worrying about memory
management, making Java a popular choice for building complex and large-scale applications. However,
understanding how Garbage Collection works is essential for Java developers to optimize their code's
performance and avoid common memory-related errors.

OutofMemoryErrors
OutofMemoryError is a type of error that occurs when a program or application attempts to allocate more
memory than the available amount. This error occurs when the Java Virtual Machine (JVM) or another platform
runs out of memory while trying to run an application.
An OutofMemoryError typically occurs when an application or program tries to create new objects, but the
JVM is unable to allocate memory to accommodate them. This error can also occur when an application is using
too much memory and is not releasing it properly.
When an OutofMemoryError occurs, the application will usually crash and terminate. This error is common in
programs that deal with large amounts of metadata, such as an image or video processing applications, or
programs that handle large databases.
To resolve this error, you may need to increase the amount of memory available to the application or optimize
the application's memory usage. This can be done by modifying the JVM parameters or by using a memory
profiler tool to identify memory leaks or inefficient memory usage.

How does garbage collection work in Java?


In Java, all objects are stored on the heap, which is a portion of memory that is reserved for dynamic allocation
of objects. When an object is no longer being referenced by any part of the program, it becomes eligible for
garbage collection.
The garbage collector in Java periodically scans the heap memory to find objects that aren’t being used. The
process of garbage collection involves several steps, including marking, sweeping, and compacting.
●​ Marking - The first step of garbage collection involves marking all objects that are still being referenced
by the program. This is done by starting with a set of root objects, such as global variables, local
variables, and method parameters, and then tracing all the objects that are reachable from those roots.
Objects that cannot be reached from the roots are considered eligible for garbage collection.
●​ Sweeping - After the marking phase, the garbage collector sweeps through the Java heap to identify and
reclaim the memory that is used by the objects that are no longer being referenced. This involves
deallocating the memory that is used by the unused objects, and adding it back to the free memory pool.
●​ Compacting - In some garbage collection algorithms, the sweeping phase is followed by a compaction
phase, where the memory that is used by the remaining objects is rearranged to minimize fragmentation.
This involves moving objects closer together and creating larger contiguous blocks of free memory.
The Java virtual machine (JVM) automatically performs garbage collection, so the programmer does not have to
manually manage memory. The garbage collector runs on a separate thread and typically operates in the
background, so it doesn't affect the normal execution of the program.
Types of garbage collectors in Java
There are two main types of Garbage Collection algorithms in Java: Full Garbage Collection and Incremental
Garbage Collection.
Full or Major Garbage Collection
Full garbage collection is a process in which a garbage collector (a part of a programming language's runtime
system) searches through all of the memory that is used by a program and compiles any objects that are no
longer being used by the program. These objects are then marked as garbage and are eligible for removal from
memory.
Full garbage collection is typically performed by the runtime system of a programming language that uses
automatic memory management, such as Java or Python. During the process, the garbage collector pauses the
program's execution to perform the search for garbage objects, which can result in a temporary slowdown in the
program's performance.
Full garbage collection is usually triggered when the amount of memory that is used by a program reaches a
certain threshold or when the program requests a new block of memory, and there is not enough free memory
available. The goal of full garbage collection is to reclaim memory that isn’t needed by the program, making it
available for use by other parts of the program or by other programs running on the same machine.

Incremental or Minor Garbage Collection


Incremental garbage collection is a type of memory management technique that is used by programming
languages and runtime environments to automatically reclaim memory that is no longer needed by a program. It
does so by identifying objects in memory that aren’t being used, and freeing up the memory they occupy so that
it can be reused by other parts of the program.
In incremental garbage collection, the garbage collector periodically scans the program's memory for
unreachable objects in the young generation's heap memory. Instead of stopping the program's execution during
this scanning process, the garbage collector divides the scanning process into small, manageable pieces called
"increments". During each increment, the garbage collector scans a portion of the program's memory,
identifying any objects that are not needed and marking them as available for reuse.
By using increments, the garbage collector can reclaim memory in small chunks, without interrupting the
program's execution for an extended period. This helps to ensure that the program remains responsive and
doesn't experience significant pauses or delays as a result of the garbage collection process.
However, incremental garbage collection can be less efficient than other types of garbage collection techniques,
such as mark-and-sweep or generational garbage collection, because it requires more frequent scans of the
program's memory. Additionally, the use of increments can introduce some overhead into the program's
execution, as the garbage collector needs to maintain state information between each increment.
Java garbage collection benefits

Overall, Java's garbage collection provides many benefits that make it a valuable tool for developers. Here are
some benefits of using Java's garbage collection:

1.​No manual memory management


2.​Prevents memory leaks
3.​Dynamic memory allocation
4.​Better performance
5.​Memory optimization
●​ No manual memory management: With garbage collection, developers do not have to manually
manage memory allocation and deallocation. This means that programmers can focus more on writing
code and less on managing memory, which can help reduce errors and improve productivity.
●​ Prevents memory leaks: Garbage collection helps prevent memory leaks, which can occur when a
program does not release memory that is no longer needed. This can cause the program to consume
more memory than necessary, leading to slow performance, and eventually crashing.
●​ Dynamic memory allocation: Java's garbage collection enables dynamic memory allocation, which
means that memory is allocated as needed at runtime. This helps prevent memory allocation errors and
can make the program more efficient.
●​ Better performance: Garbage collection can help improve the performance of a program by reducing
the amount of time spent managing memory. This can lead to faster execution times and a more
responsive program.
●​ Memory optimization: Garbage collection can optimize the use of memory by reusing memory that is
not used by one part of the program for other parts of the program. This can help reduce memory usage
and improve overall program efficiency.

Developers benefit from Java garbage collection’s ability to automatically manage memory, prevent memory
leaks, enable dynamic memory allocation, improve performance, and optimize memory usage, garbage
collection can help developers write better, more efficient programs.
What events trigger Java garbage collection?

In Java, garbage collection is triggered automatically by the JVM (Java Virtual Machine) when it determines
that the heap is getting full or when a certain amount of time has passed.

There are several events that can trigger garbage collection in Java:

●​ Heap space allocation: When the JVM needs to allocate memory for a new object, and there is not
enough space in the heap, it triggers garbage collection to reclaim unused memory or store them in the
survivor space.
●​ System.gc() method call: You can explicitly request garbage collection by calling the System.gc()
method, although there is no guarantee that it will run.
●​ Old generation threshold: Garbage collection can also be triggered when the heap size of the old
generation heap space (which stores long-lived objects) reaches a certain threshold.
●​ PermGen/Metaspace threshold: In Java versions before Java 8, garbage collection can also be
triggered when the size of the PermGen (Permanent Generation) or Metaspace (in Java 8 and later)
memory areas reaches a certain threshold.
●​ Time-based: Sometimes, garbage collection can be triggered based on a time interval. For example, the
JVM might trigger garbage collection every hour or every day, regardless of memory usage.

It's worth noting that the exact behavior of garbage collection in Java can vary depending on the JVM
implementation and configuration.
How to request JVM to run Garbage Collector

To request the Java Virtual Machine (JVM) to run garbage collector, you can follow these steps:

1.​ Call the System.gc() method: This method is used to request the JVM to run the garbage collector. It is
not guaranteed that the garbage collector will run immediately after this method is called.
2.​ Use the Runtime.getRuntime().gc() method: This method is similar to the System.gc() method, but it
is less likely to be overridden by the JVM implementation.
3.​ Use the -XX:+DisableExplicitGC JVM flag: This flag disables explicit garbage collection requests.
This means that even if you call System.gc() or Runtime.getRuntime().gc(), the garbage collector will
not be triggered.
It's important to note that explicitly requesting the garbage collector to run is generally not recommended, as the
JVM is designed to automatically manage memory allocation and garbage collection. Explicit garbage
collection requests can sometimes have a negative impact on performance.
What garbage collectors are available for Java?

There are several java garbage collectors, including:


1.​Serial Garbage Collector
2.​Parallel Garbage Collector
3.​Concurrent Mark Sweep (CMS) Collector
4.​G1 Garbage Collector
●​ Serial Garbage Collector: The Serial Collector is the default garbage collector in Java and is typically
used in small to medium-sized applications that do not require high throughput. This type of collector
helps prevent the common “stop the world” events from occurring.
●​ Parallel Garbage Collector: The Parallel Collector is designed for high-throughput applications and is
particularly useful in applications that require large heaps because it uses multiple CPUs to speed up the
process. It’s important to note that this type of collector freezes application threads when you run a
garbage collector.
●​ Concurrent Mark Sweep (CMS) Collector: The CMS Collector is designed for applications that
require low pause times and is useful in applications that have many live objects.
●​ G1 Garbage Collector: The G1 Collector is designed for large heaps and can handle a mix of short and
long-lived objects. It uses multiple threads to concurrently scan and compact the heap.

Each garbage collector has its own strengths and weaknesses, and the choice of which collector to use depends
on the specific needs of the application. It is also possible to configure and tune the garbage collector settings to
optimize performance for a particular application.
Method Overriding

Overriding in Java occurs when a subclass implements a method which is already defined in
the superclass or Base Class. The method in the subclass must have the same signature as in
the superclass.

Method overriding is a key concept in Java that enables Run-time polymorphism. It allows a
subclass to provide its specific implementation for a method inherited from its parent class.
The actual method executed is determined by the object’s runtime type, not just the reference
variable’s type.

Rule for Method Overriding

1)​ An overriding method’s access modifier in a subclass can be more permissive (e.g.,
protected to the public) than the overridden method in the superclass. However,
reducing the access level (e.g., making a protected method private) is not allowed and
will result in a compile-time error.
2)​ Final methods cannot be override.
3)​ Private methods cannot be overridden as they are bonded during compile time.
4)​ Method must have the same return type (or subtype)
5)​ Static methods cannot be override(Method Hiding)

Covariant Return Type


Java version 5.0 onwards it is possible to have different return types for an overriding
method in the child class, but the child’s return type should be a subtype of the parent’s
return type. The overriding method becomes variant with respect to return type.This process
is known as Covariant Return Type.
Exception Handling
Exception
Definition: An exception is an event, which occurs during the execution of a
program, that disrupts the normal flow of the program's instructions.

When an error occurs within a method, the method creates an object and hands it
off to the runtime system. The object, called an exception object, contains
information about the error, including its type and the state of the program when
the error occurred. Creating an exception object and handing it to the runtime
system is called throwing an exception.

After a method throws an exception, the runtime system attempts to find


something to handle it. The set of possible "somethings" to handle the exception
is the ordered list of methods that had been called to get to the method where the
error occurred. The list of methods is known as the call stack (see the next
figure).

The call stack.

The runtime system searches the call stack for a method that contains a block of
code that can handle the exception. This block of code is called an exception
handler. The search begins with the method in which the error occurred and
proceeds through the call stack in the reverse order in which the methods were
called. When an appropriate handler is found, the runtime system passes the
exception to the handler. An exception handler is considered appropriate if the
type of the exception object thrown matches the type that can be handled by the
handler.

The exception handler chosen is said to catch the exception. If the runtime
system exhaustively searches all the methods on the call stack without finding an
appropriate exception handler, as shown in the next figure, the runtime system
(and, consequently, the program) terminates.
Searching the call stack for the exception handler.

The Three Kinds of Exceptions

1)​The first kind of exception is the checked exception. These are exceptional
conditions that a well-written application should anticipate and recover
from. For example, suppose an application prompts a user for an input file
name, then opens the file by passing the name to the constructor
for java.io.FileReader. Normally, the user provides the name of an existing,
readable file, so the construction of the FileReader object succeeds, and the
execution of the application proceeds normally. But sometimes the user
supplies the name of a nonexistent file, and the constructor
throws java.io.FileNotFoundException. A well-written program will catch
this exception and notify the user of the mistake, possibly prompting for a
corrected file name.Checked exceptions are subject to the Catch or Specify
Requirement. All exceptions are checked exceptions, except for those
indicated by Error, RuntimeException, and their subclasses.
2)​The second kind of exception is the error. These are exceptional conditions
that are external to the application, and that the application usually cannot
anticipate or recover from. For example, suppose that an application
successfully opens a file for input, but is unable to read the file because of a
hardware or system malfunction. The unsuccessful read will
throw java.io.IOError. An application might choose to catch this exception,
in order to notify the user of the problem — but it also might make sense
for the program to print a stack trace and exit.Errors are not subject to the
Catch or Specify Requirement. Errors are those exceptions indicated
by Error and its subclasses.
3)​The third kind of exception is the runtime exception. These are exceptional
conditions that are internal to the application, and that the application
usually cannot anticipate or recover from. These usually indicate
programming bugs, such as logic errors or improper use of an API. For
example, consider the application described previously that passes a file
name to the constructor for FileReader. If a logic error causes a null to be
passed to the constructor, the constructor will throw NullPointerException.
The application can catch this exception, but it probably makes more sense
to eliminate the bug that caused the exception to occur.Runtime
exceptions are not subject to the Catch or Specify Requirement. Runtime
exceptions are those indicated by RuntimeException and its
subclasses.Errors and runtime exceptions are collectively known
as unchecked exceptions.
Hierarchy of the Throwable class
Three exception handler components — the try, catch, throw,throws and finally

The try Block


The first step in constructing an exception handler is to enclose the code that
might throw an exception within a try block. In general, a try block looks like the
following:
try {
code
}
catch and finally blocks . . .

The catch Blocks


You associate exception handlers with a try block by providing one or
more catch blocks directly after the try block. No code can be between the end of
the try block and the beginning of the first catch block.
try {

} catch (ExceptionType name) {

} catch (ExceptionType name) {

}
Each catch block is an exception handler that handles the type of exception
indicated by its argument. The argument type, ExceptionType, declares the type
of exception that the handler can handle and must be the name of a class that
inherits from the Throwable class. The handler can refer to the exception
with name.
The catch block contains code that is executed if and when the exception handler
is invoked. The runtime system invokes the exception handler when the handler
is the first one in the call stack whose ExceptionType matches the type of the
exception thrown. The system considers it a match if the thrown object can
legally be assigned to the exception handler's argument.

The finally Block


The finally block always executes when the try block exits. This ensures that
the finally block is executed even if an unexpected exception occurs.
But finally is useful for more than just exception handling — it allows the
programmer to avoid having cleanup code accidentally bypassed by
a return, continue, or break. Putting cleanup code in a finally block is always a
good practice, even when no exceptions are anticipated.

Exceptions Thrown by a Method


The throws clause comprises the throws keyword followed by a
comma-separated list of all the exceptions thrown by that method. The clause
goes after the method name and argument list and before the brace that defines
the scope of the method; here's an example.
public void writeList() throws IOException, IndexOutOfBoundsException {}

The throw Statement


All methods use the throw statement to throw an exception. The throw statement
requires a single argument: a throwable object. Throwable objects are instances
of any subclass of the Throwable class. Here's an example of a throw statement.
throw someThrowableObject;
Chained Exceptions
An application often responds to an exception by throwing another exception. In
effect, the first exception causes the second exception. It can be very helpful to
know when one exception causes another. Chained Exceptions help the
programmer do this. The following example shows how to use a chained
exception.
try {

} catch (IOException e) {
throw new SampleException("Other IOException", e);
}
In this example, when an IOException is caught, a
new SampleException exception is created with the original cause attached and
the chain of exceptions is thrown up to the next higher level exception handler.
Stack Trace
Definition: A stack trace provides information on the execution history of the
current thread and lists the names of the classes and methods that were called at
the point when the exception occurred. A stack trace is a useful debugging tool
that you'll normally take advantage of when an exception has been thrown.
The following code shows how to call the getStackTrace method on the
exception object.
catch (Exception cause) {
StackTraceElement elements[] = cause.getStackTrace();
for (int i = 0, n = elements.length; i < n; i++) {
System.err.println(elements[i].getFileName()
+ ":" + elements[i].getLineNumber()
+ ">> "
+ elements[i].getMethodName() + "()");
}
}
Logging API
The next code snippet logs where an exception occurred from within
the catch block. However, rather than manually parsing the stack trace and
sending the output to System.err(), it sends the output to a file using the logging
facility in the java.util.logging package.
try {
Handler handler = new FileHandler("OutFile.log");
Logger.getLogger("").addHandler(handler);

} catch (IOException e) {
Logger logger = Logger.getLogger("package.name");
StackTraceElement elements[] = e.getStackTrace();
for (int i = 0, n = elements.length; i < n; i++) {
logger.log(Level.WARNING, elements[i].getMethodName());
}
}
Java Errors vs Exceptions
According to the official documentation, an error “indicates serious problems
that a reasonable application should not try to catch.” This refers to problems that
the application can not recover from - they should be dealt with by modifying
application architecture or by refactoring code.
Here is an example of a method that throws a error, which is not handled in code:
public static void print(String myString) {
print(myString);
}
In this example, the recursive method “print” calls itself over and over again until
it reaches the maximum size of the Java thread stack, at which point it exits with
a StackOverflowError:

Exception in thread "main" java.lang.StackOverflowError


at StackOverflowErrorExample.print(StackOverflowErrorExample.java:6)
As seen above, the method throws the error during execution but does not handle
it in code - the program simply exits when the error occurs since it is
irrecoverable and requires a change in the code itself.
Exceptions, on the other hand, indicate “conditions that a reasonable application
might want to catch.” These could include problems that can occur at
compile-time (checked exceptions) or run-time (unchecked exceptions) and can
happen rather frequently in most applications - especially during development.
Checked exceptions should be handled in application code, whereas unchecked
exceptions don’t need to be handled explicitly.
Checked vs Unchecked Exceptions
Checked Exceptions

Exceptions that can occur at compile-time are called checked exceptions since
they need to be explicitly checked and handled in code. Classes that directly
inherit Throwable - except RuntimeException and Error - are checked exceptions
e.g. IOException, InterruptedException etc.

Here is an example of a method that handles a checked exception:


public void writeToFile() {
try (BufferedWriter bw = new BufferedWriter(new FileWriter("myFile.txt"))) {
bw.write("Test");
} catch (IOException ioe) {
ioe.printStackTrace();
}
}

In this example, both statements within the try block (the instantiation of
the BufferedWriter object and writing to file using the object) can
throw IOException, which is a checked exception and therefore needs to be
handled either by the method or its caller. In the example, IOException is
handled within the method and the exception stack trace is printed to the console.

Furthermore, the BufferedWriter object is a resource, which should be closed


when it is no longer needed and closing it can throw an IOException as well. In
such cases where closing resources themselves can throw exceptions, using a
try-with-resources block is best practice since this takes care of the closing of
resources automatically. The example shown earlier uses try-with-resources for
exactly this reason.

While checked exceptions force explicit handling, this doesn't necessarily lead to
better code. In fact, many modern Java frameworks and libraries prefer
unchecked exceptions for their cleaner API design. The Spring framework, for
instance, translates checked exceptions into unchecked ones to avoid cluttering
method signatures.
Unchecked Exceptions

Unchecked exceptions can be thrown "at any time" (i.e. run-time). Therefore,
methods don't have to explicitly catch or throw unchecked exceptions. Classes
that inherit RuntimeException are unchecked exceptions
e.g. ArithmeticException, NullPointerException.

Here is an example of a method that throws an unchecked exception


(NullPointerException) which is not handled in code:
public void writeToFile() {
try (BufferedWriter bw = null) {
bw.write("Test");
} catch (IOException ioe) {
ioe.printStackTrace();
}
}

When the above method is called, a NullPointerException is thrown because the


BufferedWriter object is null:

Exception in thread "main" java.lang.NullPointerException


at IOExceptionExample.writeToFile(IOExceptionExample.java:10)
at IOExceptionExample.main(IOExceptionExample.java:17)

As mentioned, since NullPointerException is an unchecked exception, it did not


need to be handled in code - only the checked exception (IOException) was
handled.

Throwable class
public class Throwable
extends Object
implements Serializable

The Throwable class is the superclass of all errors and exceptions in the Java
language. Only objects that are instances of this class (or one of its subclasses)
are thrown by the Java Virtual Machine or can be thrown by the
Java throw statement.

Constructor Summary

Throwable()​
Constructs a new throwable with null as its detail message.

Throwable(String message)​
Constructs a new throwable with the specified detail message.

Throwable(String message, Throwable cause)​


Constructs a new throwable with the specified detail message and cause.

Throwable(Throwable cause)​
Constructs a new throwable with the specified cause and a detail message
of (cause==null ? null : cause.toString()) (which typically contains the class and
detail message of cause).

Method Summary

Throwable fillInStackTrace()​
Fills in the execution stack trace.

Throwable getCause()​
Returns the cause of this throwable or null if the
cause is nonexistent or unknown.

String getLocalizedMessage()​
Creates a localized description of this throwable.
String getMessage()​
Returns the detail message string of this throwable.

StackTraceElement[] getStackTrace()​
Provides programmatic access to the stack trace
information printed by printStackTrace().

Throwable initCause(Throwable cause)​


Initializes the cause of this throwable to the
specified value.

void printStackTrace()​
Prints this throwable and its backtrace to the
standard error stream.

void printStackTrace(PrintStream s)​


Prints this throwable and its backtrace to the
specified print stream.

void printStackTrace(PrintWriter s)​


Prints this throwable and its backtrace to the
specified print writer.

void setStackTrace(StackTraceElement[] stackTrace)​


Sets the stack trace elements that will be returned
by getStackTrace() and printed by printStackTrace() and
related methods.

String toString()​
Returns a short description of this throwable.

Methods inherited from class java.lang.Object

clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
Instances of two subclasses, Error and Exception, are conventionally used to
indicate that exceptional situations have occurred.
Error class
java.lang.Object
java.lang.Throwable
java.lang.Error

An Error is a subclass of Throwable that indicates serious problems that a


reasonable application should not try to catch. Most such errors are abnormal
conditions. The ThreadDeath error, though a "normal" condition, is also a
subclass of Error because most applications should not try to catch it.

A method is not required to declare in its throws clause any subclasses


of Error that might be thrown during the execution of the method but not caught,
since these errors are abnormal conditions that should never occur.

Constructor Summary

Error()​
Constructs a new error with null as its detail message.

Error(String message)​
Constructs a new error with the specified detail message.

Error(String message, Throwable cause)​


Constructs a new error with the specified detail message and cause.

Error(Throwable cause)​
Constructs a new error with the specified cause and a detail message
of (cause==null ? null : cause.toString()) (which typically contains the class and
detail message of cause).

Method Summary

Methods inherited from class java.lang.Throwable


fillInStackTrace, getCause, getLocalizedMessage, getMessage, getStackTrace, ini
tCause, printStackTrace, printStackTrace, printStackTrace, setStackTrace, toStrin
g

Methods inherited from class java.lang.Object

clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait

Exception class
java.lang.Object
java.lang.Throwable
java.lang.Exception

Constructor Summary

Exception()​
Constructs a new exception with null as its detail message.

Exception(String message)​
Constructs a new exception with the specified detail message.

Exception(String message, Throwable cause)​


Constructs a new exception with the specified detail message and cause.

Exception(Throwable cause)​
Constructs a new exception with the specified cause and a detail message
of (cause==null ? null : cause.toString()) (which typically contains the class and
detail message of cause).

You might also like