How do I determine MaxDirectMemorySize on a running JVM? - java

I have an application which uses DirectByteBuffers to store data, but I'd like to know what MaxDirectMemorySize is so I don't accidentally exceed it.
Without configuring this manually, how can I figure out, from within the program, what MaxDirectMemorySize is?

The accepted answer only works if the option is explicitly specified on the command line. As of Java 6, you can access the option directly using the HotSpotDiagnosticMXBean. The following Java 7 code can read it conveniently:
final HotSpotDiagnosticMXBean hsdiag = ManagementFactory
.getPlatformMXBean(HotSpotDiagnosticMXBean.class);
if (hsdiag != null) {
System.out.println(hsdiag.getVMOption("MaxDirectMemorySize"));
}
Note that this may return a value of zero, meaning to use the default setting, which is equal to Runtime.getRuntime().maxMemory(). For example, with Oracle JDK 7u71 64-bit on Windows 7, this returns 3,690,987,520.
Alternatively, if you're willing to resort to accessing the sun.misc package, it's available directly by calling sun.misc.VM.maxDirectMemory().

Yuu can get ALL JVM parameters with...
RuntimeMXBean RuntimemxBean = ManagementFactory.getRuntimeMXBean();
List<String> args=RuntimemxBean.getInputArguments();
for(int i=0;i<args.size();i++) {
System.out.println(args.get(i));
}

Related

How to configure Java heap size for node.js JDBC module?

In my node.js application, I'm using JDBC to connect to a Oracle database. I need to increase my java heap space to prevent following error:
java.lang.OutOfMemoryError: Java heap space
I know that there is a terminal option for setting maximum Java heap size (-Xmx<size>) but the problem is, I don't explicitly run java, it happens inside my JDBC module (which depends on java module), so I can't use that terminal option.
So how java heap size can be configured in my case?
In short
I checked the source code of node-jdbc, and it's not possible at the moment.
In Detail
Refer the file jinst.js
var java = require('java');
...
module.exports = {
...
addOption: function(option) {
if (!isJvmCreated() && option) {
java.options.push(option);
} else if (isJvmCreated()) {
...
Refer the files pool.js, connection.js, resultset.js
var jinst = require("./jinst");
...
var java = jinst.getInstance();
...
if (!jinst.isJvmCreated()) {
jinst.addOption("-Xrs");
}
You will see it's only setting the option -Xrs even though the node module java is giving the flexibility of adding any java options.
Next Step
For the moment I'm not interested in this project. But If I was in your shoes I will create a pull request to the project https://github.com/CraZySacX/node-jdbc with this option as a feature.
Cheers :)

Check programatically (without string-matching) whether using IPV6 or IPV4 for JVM

I want to check whether JVM options for a particular application (in this case, Matlab) have been set to prefer IPV4 or if they still use IPV6.
I know how to set the JVM to prefer IPV4. In my case, it can be done by adding the line
-Djava.net.preferIPv4Stack=true
to the java.opts file within $MATLABROOT/bin/maci64/.
I can also check whether this line has already been added to java.opts via string-matching. I've pasted my current solution (a Matlab script that checks for string-match, and adds the line if it does not exist) at the bottom of this question.
I don't know how, though, to check whether IPV4 or IPV6 is preferred without string-matching. Obviously this seems preferred.
Does anybody know how to check IPV4 vs. IPV6 in the JVM without string-matching?
Here's my current solution, that depends on string-matching:
% OSX platform-specific: revert to IPv4
if (computer('arch') == 'maci64')
javaoptspath = fileread([matlabroot '/bin/' computer('arch') '/java.opts']);
k = strfind(javaoptspath, '-Djava.net.preferIPv4Stack=true');
if isempty(k)
setenv('DRAKE_IPV4_SET_MATLABROOT', matlabroot)
setenv('DRAKE_IPV4_SET_ARCH', computer('arch'))
display('Since you are on Mac, we will need to set your JVM to prefer IPV4 instead of IPV6 for MATLAB')
display('Please enter your sudo password below')
! (echo "" | echo "-Djava.net.preferIPv4Stack=true") | sudo tee -a $DRAKE_IPV4_SET_MATLABROOT/bin/$DRAKE_IPV4_SET_ARCH/java.opts
end
end
You can access the underlying java system properties without parsing the options string by using the java.lang.System class directly from Matlab.
For example:
ipv4_preferred = java.lang.System.getProperty('java.net.preferIPv4Stack')
The result of getProperty will be empty if the user has not set -Djava.net.preferIPv4Stack=..., so a more complete solution might be:
ipv4_preferred = java.lang.System.getProperty('java.net.preferIPv4Stack');
if isempty(ipv4_preferred)
ipv4_preferred = false;
end

Java 1.4.2 File.listFiles not working properly with CIFS mounts - workaround?

I'm using Java 1.4.2 and Debian 6.0.3. There's a shared Windows folder in the network, which is correctly mounted to /mnt/share/ via fstab (e.g. it's fully visible from OS and allows all operations) using CIFS. However, when I try to do this in Java:
System.out.println(new File("/mnt/share/").listFiles().length)
it would always return 0, meaning File[] returned by listFiles is empty. The same problem applies to every subdirectory of /mnt/share/. list returns empty array as well. Amusingly enough, other File functions like "create", "isDirectory" or even "delete" work fine. Directories mounted from USB flash drive (fat32) also work fine.
I tested this on 2 different "shared folders" from different Windows systems; one using domain-based authentication system, another using "simple sharing" - that is, guest access. The situation seems weird, since mounted directories should become a part of a file system, so any program could use it. Or so I thought, at least.
I want to delete a directory in my program, and I currently see no other way of doing it except recursive walking on listFiles, so this bug becomes rather annoying. The only "workaround" I could think of is to somehow run an external bash script, but it seems like a terrible solution.
Edit: It seems this is 1.4.2-specific bug, everything works fine in Java 6. But I can't migrate, so the problem remains.
Could you suggest some workaround? Preferably without switching to third-party libs instead of native ones, I can't say I like the idea of rewriting the whole project for the sake of single code line.
Since Java 1.2 there is method File.getCanonicalFile(). In your case with mounted directory you should use exactly this one in such style:
new File("/mnt/share/").getCanonicalFile().listFiles()
So, two and half years later after giving up I encounter the same problem, again stuck with 1.4.2 because I need to embed the code into obsolete Oracle Forms 10g version.
If someone, by chance, stumbles onto this problem and decides to solve it properly, not hack his way through, it most probably has to do with (highly) unusual inode mapping that CIFS does upon mounting the remote filesystem, causing more obscure bugs some of which can be found on serverfault. One of the side-effects of such mapping is that all directories have zero hard-link count. Another one is that all directories have "size" of exactly 0, instead of usual "sector size or more", which can be checked even with ls.
I can't be sure without examining the (proprietary) source code, but I can guess that Java prior to 1.5 used some shortcut like checking link count internally instead of actually calling readdir() with C, which works equally well for any mounted FS.
Anyway, the second side-effect can be used to create a simple wrapper around File which won't rely on system calls unless it suspects a directory is mounted using CIFS. Other versions of list and listFiles functions in java.io.File, even ones using filters, rely on list() internally, so it's OK to override only it.
I didn't care about listFiles returning File[] not FileEx[] so I didn't bother to override it, but is should be simple enough. Obviously, that code can work only in Unix-like systems having ls command handy.
package FSTest;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
public class FileEx extends File
{
public FileEx(String path)
{
super(path);
}
public FileEx(File f)
{
super(f.getAbsolutePath());
}
public String[] list()
{
if (this.canRead() && this.isDirectory())
{
/*
* Checking the length of dir is not the most reliable way to distinguish CIFS mounts.
* However, zero directory length generally indicates something unusual,
* so calling ls on it wouldn't hurt. Ordinary directories don't suffer any overhead this way.
* If this "zero-size" behavior is ever changed by CIFS but list() still won't work,
* it will be safer to call super.list() first and call this.listUsingExec if returned array has 0 elements.
* Though it might have serious performance implications, of course.
*/
if (this.length() > 0)
return super.list();
else
return this.listUsingExec();
}
else
return null;
}
private String[] listUsingExec()
{
Process p;
String command = "/bin/ls -1a " + this.getAbsolutePath();
ArrayList list = new ArrayList();
try
{
p = Runtime.getRuntime().exec(command);
p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
for (String line = reader.readLine(); line != null; line = reader.readLine())
{
if (!line.equalsIgnoreCase(".") && !line.equalsIgnoreCase(".."))
list.add(line);
}
String[] ret = new String[list.size()];
list.toArray(ret);
return ret;
}
catch (IOException e)
{
return null;
}
}
}

Does Java have an equivalent to C#'s Environment.GetCommandLineArgs()?

I know that I can get the command-line arguments in the "main" method, but I need to be able to get them indirectly.
Thanks for your help.
Following expression is exactly what you want:
System.getProperty("sun.java.command")
You can list the threads, find the main thread, and crawl down the stack trace until you find the call to main, and pull out the args.
update a comment points out that this won't work all by itself, and I think the comment is correct. I misremembered the capabilities of stack introspection or mentally mixed in JVMTI.
So, here's plan B. Connect to yourself with JMX. The VM Summary MBean has the args.
Connection name: 
pid: 77090 com.basistech.jdd.JDDLauncher -config src/main/config/benson-laptop-config.xml
All this having been said, what you should do is call System.getProperty and live with the need to use -D to pass parameters from the outside world down into your cave.
You could write a wrapper to take the cli and re-format it to use -DPROP=VAL
int main(int argc, char*argv[])
{
std::vector<std::string> in (argv+1,argv+argc), out();
out.push_back("java.exe");
out.push_back("-cp");
out.push_back("my-jar.jar");
out.push_back("main.class")
for( auto it = in.begin(); it!=in.end(); ++in)
{
//process CLI args. turn "-abc","BLAH" into "-Darg.a=true","-Darg.b=true","-Darg.c=BLAH" and push to out
//Do additional processing. Maybe evn use get_opt() or Boost.ProgramOptions
}
//use exec or CreateProcess to launch java with the proper args
//or even use something like WinRun4J's methods to load the jvm.dll
//Then your program shows up as "MyExe.exe" instead of "java.exe"
//Use System.getProperty("arg.a","false") to get the value of a
}
Of course, you could always just tell you users to invoke a bash/batch script with the proper -DA=true type arguments

Is it possible for e JUnit test to tell if it's running in Eclipse (rather than ant)

I have a test that compares a large blob of expected XML with the actual XML received. If the XML is significantly different, the actual XML is written to disk for analysis and the test fails.
I would prefer to use assertEquals so that I can compare the XML more easily in Eclipse - but this could lead to very large JUnit and CruiseControl logs.
Is there a way I can change a JUnit test behaviour depending on whether it's running through Eclipse or through Ant.
Here are 2 solutions.
Use system properties
boolean isEclipse() {
return System.getProperty("java.class.path").contains("eclipse");
}
Use stacktrace
boolean isEclipse() {
Throwable t = new Throwable();
StackTraceElement[] trace = t.getStackTrace();
return trace[trace.length - 1].getClassName().startsWith("org.eclipse");
}
Yes - you can test if certain osgi properties are set (System.getProperty("osgi.instance.area") for instance). They will be empty if junit is started through ant outside of eclipse.
Maybe the "java.class.path" approach can be weak if you include some eclipse jar in the path.
An alternative approch could be to test "sun.java.command" instead:
On my machine (openjdk-8):
sun.java.command org.eclipse.jdt.internal.junit.runner.RemoteTestRunner ...
A possible test:
boolean isEclipse() {
return System.getProperty("sun.java.command")
.startsWith("org.eclipse.jdt.internal.junit.runner.RemoteTestRunner");
}
Usually, the system proeprties are different in different environments. Try to look for a system property which is only set by eclipse or ant.
BTW: The output in eclipse is the same, its just that the console for eclipse renders the output in a more readable form.
Personally, I wouldn't worry about the size of the logs. Generally you don't need to keep them very long and disk space is cheap.
With Java 1.6+, it looks like the result of System.console() makes a difference between running for Eclipse or from a terminal:
boolean isRealTerminal()
{
// Java 1.6+
return System.console() != null;
}

Categories

Resources