Why doesn't GC collect objects without references? - java

public static void main(String[] args) {
try {
Path file = Paths.get("file.jar"); // 100mb file
for (int i = 0; i < 10; i++) {
byte[] toCollect = Files.readAllBytes(file);
toCollect = null;
}
System.gc();
} catch (Exception e) {
e.printStackTrace();
}
new Thread(() - > {
try {
Thread.sleep(100000000L);
} catch (Exception e) {
e.printStackTrace();
}
}).start();
}
After executing this code the program uses 1GB of RAM, why?
This code reads bytes from a file using the JAVA API and puts them into an array, then assigns null to that array.

Related

Replacing Future<Integer> with Future<Void>

I am writing an application that searches for Java files in a given directory and its subdirectories and writes all the strings from those files in reverse order to a new folder. Each directory and file is handled in a separate thread.
At the moment my program works correctly, but I want to change its behavior.
Right now, the program overwrites the files correctly and outputs the number of overwritten files to the console at the end. I want my program to just overwrite the files and display the line "All files overwritten" at the end. But I don't quite understand how I can change my code and replace Future (I think that's my problem). Here is part of the code from the Main class:
ExecutorService pool = Executors.newCachedThreadPool();
ReverseWritter reverseWritter = new ReverseWritter(dirToSearch, dirToStorePath + "//" + dirToStoreName, pool);
Future<Integer> res = pool.submit(reverseWritter);
try {
System.out.println(res.get() + " files reversed");
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
pool.shutdown();
Here's the method that overwrites the file:
public boolean reverseWrite(File file) {
if (file.isFile() && file.toString().endsWith(".java")) {
String whereTo = dirToStorePathName + "\\" + file.getName().substring(0, file.getName().indexOf(".java")) + "Reversed" + ".java";
try ( Scanner myReader = new Scanner(file); FileWriter myWriter = new FileWriter(whereTo);) {
while (myReader.hasNextLine()) {
String data = myReader.nextLine();
myWriter.write(new StringBuffer(data).reverse().toString());
myWriter.write(System.getProperty("line.separator"));
}
} catch (FileNotFoundException e) {
System.out.println("An error occurred.");
e.printStackTrace();
return false;
} catch (IOException e) {
System.out.println("An error occurred.");
e.printStackTrace();
return false;
}
}
return true;
}
And this is the call method (my class implements the Callable interface):
#Override
public Integer call() {
int count = 0;
try {
File[] files = dirToSearch.listFiles();
ArrayList<Future<Integer>> result = new ArrayList<>();
for (File f : files) {
if (f.isDirectory()) {
ReverseWritter reverseWritter = new ReverseWritter(f, dirToStorePathName, pool);
Future<Integer> rez = pool.submit(reverseWritter);
result.add(rez);
} else if (reverseWrite(f)) {
count++;
}
for (Future<Integer> rez : result) {
count += rez.get();
}
}
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
return count;
}
You just need to change the class to implement Callable<Void> and remove the operations which do the counting. Change the return type of call from Integer to Void.
public class ReverseWriterCallable implements Callable<Void> {
#Override
public Void call() throws Exception {
//do stuff
//don't do the counting operations
//when return type is Void you can only return null
return null;
}
}
Or implement Runnable and submit it to the executor service.
public class ReverseWriterRunnable implements Runnable {
#Override
public void run() {
//do stuff
//don't do the counting operations
}
}
Then just don't care about the result of the Future:
try {
res.get();
System.out.println("All files reversed");
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
pool.shutdown();

Read multiple different objects in a text file - Java

I'm working on a school project which consist in creating race-tournaments
I'm having an issue right now because I have multiple races-type (CarRace/BikeRace) which have Race as a parent
I'm saving an array of races no matter the specific type.
And now I need to load this list of races
public static ArrayList<Course> loadLRace(String name) {
File inFile = new File(name+".txt");
FileInputStream inFileStream;
ArrayList<Race> lRace = new ArrayList<Race>();
try {
inFileStream = new FileInputStream(inFile);
ObjectInputStream inObjectStream = new ObjectInputStream(inFileStream);
int length = inObjectStream.readInt();
for(int i = 0; i < length; i++) {
Race race = (Race)inObjectStream.readObject();
lRace.add(Race);
}
inObjectStream.close();
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
catch (ClassNotFoundException e) {
e.printStackTrace();
}
return lRace;
}
And I'm having a "non valid constructor" error, I guess this is because I don't deal with CarRace AND BikeRace separately, but how can I ?

Java File.deleteOnExit() not working Windows 10

I'm trying to write code for a jarfile which if executed, it shutdowns the JVM and then deletes the jarfile. This is what I've tried to do so far but it is not deleting the file after the JVM closes.
public static void check() {
if (isJarFile()) {
try (Scanner s = new Scanner(new URL(HASH_PROVIDER).openStream())) {
String remote_hash = s.nextLine().trim();
File jarFile = getJarFile();
if (jarFile != null && !remote_hash.equals(getMD5Checksum(jarFile.getAbsolutePath()))) {
jarFile.setWritable(true);
jarFile.deleteOnExit();
}
System.exit(0);
} catch (Exception e) {
e.printStackTrace();
System.exit(0);
}
}
}
public static byte[] createChecksum(String filename) throws Exception {
InputStream fis = new FileInputStream(filename);
byte[] buffer = new byte[1024];
MessageDigest complete = MessageDigest.getInstance("MD5");
int numRead;
do {
numRead = fis.read(buffer);
if (numRead > 0) {
complete.update(buffer, 0, numRead);
}
} while (numRead != -1);
fis.close();
return complete.digest();
}
public static String getMD5Checksum(String filename) throws Exception {
byte[] b = createChecksum(filename);
String result = "";
for (int i = 0; i < b.length; i++) {
result += Integer.toString((b[i] & 0xff) + 0x100, 16).substring(1);
}
return result;
}
public static File getJarFile() {
try {
return new File(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI().getPath());
} catch (URISyntaxException e) {
e.printStackTrace();
}
return null;
}
Can someone explain why deleteOnExit is not working in this instance?
Make sure that you close any stream that you have open on a file before exiting your JVM. Otherwise, the shut down hook that is supposed to delete the file cannot trigger on Windows as opening the stream triggers a file lock on the OS-level.
For your example, it means that you must not end the JVM process before exiting the try-with-ressources-block which is roughly translated into:
Scanner s = new Scanner(new URL(HASH_PROVIDER).openStream())
try {
// your code
System.exit(0);
} finally {
s.close(); // Never executed
}
As your program exits before the finally block is executed, the shut down hook is triggered without closing the stream and the file cannot be deleted.
Note that the following code will work for your purposes as the finally block is executed after closing the try-with-ressources argument:
try (Scanner s = new Scanner(new URL(HASH_PROVIDER).openStream())) {
// your code
} catch (Exception e) {
e.printStackTrace();
} finally {
System.exit(0);
}

cmd command from java application error

Recently I added "adb devices" in the nano ./bash_profile so that I can run it from any directory.
I used one java application to run
public static void main(String [] args) {
executeCmd("adb devices");
}
private static void executeCmd(String string) {
InputStream pipedOut = null;
try {
Process aProcess = Runtime.getRuntime().exec(string);
// These two thread shall stop by themself when the process end
Thread pipeThread = new Thread(new StreamGobber(aProcess.getInputStream()));
Thread errorThread = new Thread(new StreamGobber(aProcess.getErrorStream()));
pipeThread.start();
errorThread.start();
aProcess.waitFor();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException ie) {
ie.printStackTrace();
}
}
class StreamGobber implements Runnable {
private InputStream Pipe;
public StreamGobber(InputStream pipe) {
if(pipe == null) {
throw new NullPointerException("bad pipe");
}
Pipe = pipe;
}
public void run() {
try {
byte buffer[] = new byte[2048];
int read = Pipe.read(buffer);
while(read >= 0) {
System.out.write(buffer, 0, read);
read = Pipe.read(buffer);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(Pipe != null) {
try {
Pipe.close();
} catch (IOException e) {
}
}
}
when I run any other commands such as "ls" it's working fine!!
I'm using mac ..
thanks :)
Maybe global path problem on mac. You can try run with absolute adb program path as command.

ExecutorService slower than sequential file process of copying file

This is my code for copying file from one directory to other using ExecutorService but it turned out to be slower than sequential operation. Am using apache FileUtils copyFile method which is not synchronized. What's the problem?
public class ExecutorService {
private static java.util.concurrent.ExecutorService pool;
public ExecutorService() {
pool = Executors.newFixedThreadPool(20);
}
public static void main(String arg[]) {
long a = System.currentTimeMillis();
new ExecutorService();
List<File> listFiles = null;
try {
listFiles = FileUtility.getFileNamesToExtract(new File(
"C:/Users/User/Desktop/XSLT Source/Input XML"));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
for (int i = 0; i < listFiles.size(); i++)
pool.submit(new FileTransfer(listFiles.get(i), i));
pool.shutdown();
try {
pool.awaitTermination(Long.MAX_VALUE, TimeUnit.NANOSECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
long b = System.currentTimeMillis();
System.out.println((b - a) / 1000);
}
}
public class FileTransfer implements Runnable{
private File file = null;
private int num = 0;
public FileTransfer(File file, int i) {
this.file = file;
this.num = i;
}
#Override
public void run() {
try {
System.out.println("Processing="+file.getName());
FileUtils.copyFile(file, new File("C:/Users/gursahibsahni/Desktop/thread pool files/"+num+"_"+file.getName()+num));
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
What's the problem?
I can't really see why you would think a thread pool can speed up file transfer. Try this: run your single-threaded version and monitor CPU usage. My expectation: it will be below 10%.
File copying is not a CPU-intensive operation and moreover, parallelizing it only means you create a difficult disk access pattern, which slows down the whole thing and probably also causes more file fragmentation.

Categories

Resources