java etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster
java etiketine sahip kayıtlar gösteriliyor. Tüm kayıtları göster

11 Eylül 2022 Pazar

java komutu Native Memory Seçenekleri

Giriş
1. Uygulama -XX:NativeMemoryTracking=... şeklinde çalıştırılır
2. Uygulamaya jcmd ile Diagnostic Command Request gönderilir ve bir çıktı alınır

Native Memory allocations through JNI - Yani native Anahtar Kelimesi
Açıklaması şöyle. "Native memory" alanına erişmek yani C kodunu çağırmak için Java'daki native anahtar kelimesi kullanılır.
Native memory is memory allocated by the OS on behalf of the Java process through C code. This C code is called by native methods in certain Java classes.
Mesela java.util.zip paketindeki bazı kodlar şöyle
private static native void initIDs();
private native static long init(int level, int strategy, boolean nowrap);
private native static void setDictionary(long addr, byte[] b, int off, int len);
private native int deflateBytes(long addr, byte[] b, int off, int len,
                                  int flush);
private native static int getAdler(long addr);
private native static void reset(long addr);
private native static void end(long addr);
Neden Native Anahtar Kelimesi
Açıklaması şöyle. Sebep performans
The final possibility of native memory allocation from the JVM comes from libraries backed by native code. In some cases it makes more sense to implement functionality as native code, generated by compilers for languages such as C, C++ or Rust. Native code can perform better, or it might be the only way to access certain OS level functionality. Java allows calling native code through the Java Native Interface (JNI). Code called through JNI manages its own memory, so this memory is not tracked by the JVM and not automatically cleaned up through garbage collection. In a language like C, memory is managed by calling the malloc and free functions, which respectively request memory from and return memory to the OS. This is far from the complete picture, but more on that in the next level.
Native Memory Kategorileri
Açıklaması şöyle
Native memory consists of several native memory categories, such as: java heap, metaspace, thread etc.

The next table taken from Oracle’s site describes native memory categories used by NMT. Take into consideration that these categories may change with a release:
Şeklen şöyle

XX:NativeMemoryTracking seçeneği
Açıklaması şöyle. Bu seçeneği kullanınca JVM Off-heap kaynaklarını da takip etmeye başlar.
There are a few categories of native memory that the JVM can track by default, such as memory used by the garbage collector, thread stacks, loaded classes, and more. To enable JVM native memory tracking we simply pass it the -XX:NativeMemoryTracking=detail flag,
-XX:NativeMemoryTracking=... ile kullanılabilecek seçenekler şöyle
1. summary
2. detail
Örnek
Şöyle yaparız
java -XX:NativeMemoryTracking=detail -jar YourApp.jar
Örnek
Eğer testlerde kullanmak istersek şöyle yaparız
<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-surefire-plugin</artifactId>
      <configuration>
        <argLine>-XX:NativeMemoryTracking=detail</argLine>
      </configuration>
    </plugin>
  </plugins>
</build>
Açıklaması şöyle
Pay attention: Enabling NMT will result in a 5–10 percent JVM performance drop. By the way, NMT usage is also tracked by NMT.

NMT is not enabled by default. To enable this feature we need to add the following argument to the application’s JVM parameters: -XX:NativeMemoryTracking=summary

(to get a more detailed view of native memory usage, use: -XX:NativeMemoryTracking=detail)

To obtain the NMT details once the feature is enabled you should perform the following command:

jcmd <pid> VM.native_memory summary
‘<pid>’ is the PID of the application being analyzed

I ran this command manually several times and noticed a native memory category which was leaking, it was “serviceability”. After some research it was found out that there was a bug in 17.0.1 related to ThreadMXBean#dumpAllThreads method. Our application used that method. To fix the problem, I made some changes to avoid using that method (also found out that this bug was known and would be fixed in 17.0.2). After redeploying the fix and checking memory consumption, I was content, the issue disappeared.


2 Şubat 2022 Çarşamba

java komutu Permanent Space İçin -XX Seçenekleri - Kaldırıldı

Giriş
Permanent Space seçenekleri Java 8'den itibaren deprecate edildi. Java 17 ile de kaldırıldı. Açıklaması şöyle
... Permgen has been replaced by Metaspace to address some of PermGen's drawbacks (as you were able to see for yourself, one of those drawbacks is that it had a fixed size).
Yani 
-XX:PermSize ve -XX:MaxPermSize yerine 
-XX:MetaspaceSize=size ve -XX:MaxMetaspaceSize=size geldi

-XX:MaxPermSize
Permanent Space için en büyük alanı belirtir. Şöyle yaparız.
"%JAVA_HOME%\bin\java" ... -XX:MaxPermSize=256m ...
-XX:PermSize
Permanent Space için en küçük alanı belirtir. Şöyle yaparız.
%JAVA_HOME%\bin\java" ... -XX:PermSize=256m ...


12 Kasım 2021 Cuma

java komutu Off-heap İçin -X Seçenekleri

Giriş
Açıklaması şöyle. Off-heap yerine bazen "Direct Memory" de kullanılıyor.
Any memory the JVM uses besides the heap is considered off-heap. 
Off-heap bellek dışında iki bellek daha var. Bunlar
1. Direct Buffer
2. Native Memory allocations through JNI

Direct Memory vs Direct Buffer
 "Direct Memory" ve "Direct Buffer" farklı şeylerdir. Direct Buffer genelde low level I/O için kullanılır

Açıklaması şöyle
Even though the JVM does not track its direct byte buffer memory usage by default, we can measure these buffers’ sizes using a trick involving the DirectByteBuffer class. This class stores the location and size of a single direct byte buffer, so if we sum the size field of all DirectByteBuffer instances we’ll end up with our answer. There are some technicalities though. Firstly, some DirectByteBuffer instances may point at the physical memory owned by other instances (called “viewed” buffers). Secondly, DirectByteBuffer instances whose backing memory is likely already deallocated may still be around (“phantomed” or “phantom-reachable” buffers).

Luckily, there are some tools around to deal with these problems. For instance, IBM’s Eclipse Memory Analyzer extensions have a feature to calculate the size of non-viewed non-phantomed direct byte buffers.
Native Memory allocations through JNI

Off-heap İçin -X Seçenekleri

-XX:MaxDirectMemorySize seçeneği
JVM'in ne kadar "native" bellek alanı kullanabileceğini belirtir. Açıklaması şöyle.
The internal JVM limit is set as follows:

By default, it’s equal to  -Xmx. Yes, the JVM heap and off-heap memory are two different memory areas, but by default, they have the same maximum size.

The limit can be changed using -XX:MaxDirectMemorySize  property. This property accepts acronyms like “g” or “G” for gigabytes, etc.
XX:NativeMemoryTracking seçeneği

21 Ekim 2021 Perşembe

java komutu Module Seçenekleri

Giriş
Açıklaması şöyle. Eğer bir module içindeki reserved veya internal bir sınıfa erişmeye çalışırsak hata alırız.
Due to the new module system, Java 9 does not allow an application by default to see all classes from the JDK, unlike all previous versions of Java. If we try to access some reserved module, we obtain an error like this:
module <module-name> does not "opens <package-name>" to unnamed module.

Everyone knows that we can solve this exception by using the JVM parameters --add-exports or -add-opens ...
Çözüm
1. -add-modules ile module eklenir
2. --add-opens veya add-exports ile module içindeki sınıfa erişim açılır

Örnek - classpath
Şöyle yaparız. Burada module classpath içinde
java --add-modules java.se \
  --add-exports java.base/jdk.internal.ref=ALL-UNNAMED \
  --add-opens java.base/java.lang=ALL-UNNAMED \
  --add-opens java.base/java.nio=ALL-UNNAMED \
  --add-opens java.base/sun.nio.ch=ALL-UNNAMED \
  --add-opens java.management/sun.management=ALL-UNNAMED \
  --add-opens jdk.management/com.ibm.lang.management.internal=ALL-UNNAMED \
  --add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED \
  -jar hazelcast-5.2.3.jar
Örnek - classpath
Şöyle yaparız. Burada --module-path ile module belirtiliyor
java --add-modules java.se \
  --add-exports java.base/jdk.internal.ref=com.hazelcast.core \
  --add-opens java.base/java.lang=com.hazelcast.core \
  --add-opens java.base/java.nio=com.hazelcast.core \
  --add-opens java.base/sun.nio.ch=com.hazelcast.core \
  --add-opens java.management/sun.management=com.hazelcast.core \
  --add-opens jdk.management/com.ibm.lang.management.internal=com.hazelcast.core \
  --add-opens jdk.management/com.sun.management.internal=com.hazelcast.core \
  --module-path lib \ 
  --module com.hazelcast.core/com.hazelcast.core.server.HazelcastMemberStarter
--add-exports vs --add-opens
Açıklaması şöyle. Yani --add-opens ile public olan olmayan her şeye erişiliyor. --add-exports ile sadece public olanlara erişiliyor.
- With --add-exports the package is exported, meaning all public types and members therein are accessible at compile and run time.
- With --add-opens the package is opened, meaning all types and members (not only public ones!) therein are accessible at run time.

So the main difference at run time is that --add-opens allows "deep reflection", meaning access of non-public members. You can typically identify this kind of access by the reflecting code making calls to setAccessible(true).
1. --add-exports seçeneği
reserved bir sınıfa erişmek için kullanılır
Örnek
Elimizde şöyle bir kod olsun. Burada reflection yok, sadece eskinde yazılmış bir kod, yeni Java ile çalıştırılıyor ve artık BuddhistCalendar sınıfın dışarıya açılmadığı için yani reserverd/internal olduğu için hata veriyor.
BuddhistCalendar calendar = new BuddhistCalendar();


// Output
error: package sun.util is not visible
  (package sun.util is declared in module java.base, which does not export it)
Düzeltmek için şöyle yaparız
javac --add-exports java.base/sun.util=ALL-UNNAMED Foo.java
Örnek
Şöyle yaparız.
java --add-exports java.security.jgss/sun.security.krb5.internal.ktab=ALL-UNNAMED
  your-class
2. --add-opens
reserved bir module'e erişmek için kullanılır

Örnek
Elimizde şöyle bir kod olsun. Burada reflection var ve yeni Java ile çalıştırılıyor.  Artık BuddhistCalendar  sınıfın dışarıya açılmadığı için yani reserverd/internal olduğu için hata veriyor.
Class.forName("sun.util.BuddhistCalendar").getConstructor().newInstance();

//Output
Exception in thread "main" java.lang.IllegalAccessException:
  class Internal cannot access class sun.util.BuddhistCalendar (in module java.base)
  because module java.base does not export sun.util to unnamed module @1f021e6c
    at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException
      at java.base/java.lang.reflect.AccessibleObject.checkAccess
      at java.base/java.lang.reflect.Constructor.newInstanceWithCaller
      at java.base/java.lang.reflect.Constructor.newInstance
Düzeltmek için şöyle yaparız
java \
  --add-opens java.base/sun.util=ALL-UNNAMED \
  --class-path com.bar.foo.jar \
  com.bar.foo.Foo
Örnek
Şöyle yaparız.
set JAVA_OPTS=--add-modules jdk.unsupported --add-opens=java.base/java.nio=ALL-UNNAMED
3. -add-modules seçeneği
Bazı module isimleri şöyle
- java.se
- jdk.unsupported
- java.xml.bind

Örnek
Java 9 ile geçilen modül sisteminden sonra Java EE jar'larını classpath'e dahil edebilmek için şöyle yaparız.
java --add-modules java.xml.bind <class file>
Örnek
Şöyle yaparız.
java --add-modules java.se.ee -jar myspringbootproject.jar
4. --module-path veya -p seçeneği
-p ile aynıdır. Açıklaması şöyle. Yani --module-path modulepath veya -p modulepath şeklindedir.
Searches for directories from a semicolon-separated (;) list of directories. Each directory is a directory of modules.
Örnek
Şöyle yaparız.
java --module-path mymods -m com.test/com.test.HelloWorld
Örnek
jar dosyasındaki modülleri listelemek için şöyle yaparız.
java -p yourModular.jar --list-modules

21 Eylül 2021 Salı

java komutu Parametre Geçme Seçenekleri

Giriş
JVM'e parametre geçmek için iki yöntem var
1. -D seçeneğini kullanmak
2. JAVA_TOOL_OPTIONS ortam değişkenini (environment variable) kullanmak

-D seçeneği
Örnek
Şöyle yaparız.
-Dfoo.bar=foobar
Kodda parametreye erişmek için şöyle yaparız. Yani System.getProperty() kullanılır
class Foo {
  private static final String BAR;
  static {
    String foobar = System.getProperty("foo.bar");
    if(foobar != null && foobar.length()>0) {
      BAR = foobar;
    } else {
      BAR = "somedefaultvalue";
    }
  }
}
Örnek
JVM'in kullanacağı locale'i belirtmek için şöyle yaparız.
-Duser.language=de
-Duser.country=DE
Örnek
Derleyici optimizasyonunu kapatmak için şöyle yaparız.
-Djava.compiler=NONE
JAVA_TOOL_OPTIONS seçeneği
Açıklaması şöyle
When the JVM starts it search’s for this environment variable, and uses it. You can check the output of the JVM displaying a message with the values found.
Örnek
Şöyle yaparız
export JAVA_TOOL_OPTIONS=‘-Dvar1=value1 -Dvar2=value2’

29 Eylül 2020 Salı

java komutu - Uygulamayı Çalıştırır

Giriş
Söz dizimi şöyle.
java [optionsclassname [args]
Bu komutu çalıştırmak için JAVA_HOME Ortam Değişkeni'nin tanımlı olması gerekir.

java.library.path Ortam Değişkeni
Bu ortam değişkeni eğer java kodundan DLL kullanılıyorsa, DLL dosyalarının bulunduğu dizini gösterir. Linux'ta DLL yerine Shared Object (.so) dosyaları var

Linux Yöntemleri
Yöntemler şöyle
1. Call System.load to load the shared library from an explicitly specified absolute path.
Yapmayın

2. Copy the shared library to one of the paths already listed in java.library.path
Açıklaması şöyle. Yapmayın
The java.library.path is initialized from the LD_LIBRARY_PATH environment variable.
3. Modify the LD_LIBRARY_PATH environment variable to include the path where the shared library is located.
Bence en makul çözüm bu

4. Specify the java.library.path on the command line by using the -D option.
Bence en makul ikinci çözüm bu

JEP 330
JEP 330 - Running Java Files Directly  yazısına taşıdım

-add-exports seçeneği
java komutu Module Seçenekleri yazısına taşıdım

-add-modules seçeneği
java komutu Module Seçenekleri yazısına taşıdım

-classpath (ya da -cp ) seçeneği
Açıklaması şöyle.
$ java -help
    …
    -cp <class search path of directories and zip/jar files>
    -classpath <class search path of directories and zip/jar files>
                  A : separated list of directories, JAR archives,
                  and ZIP archives to search for class files.
Örnek
Şöyle yaparız.
bash$ java -classpath path/to/jars/directory MyMainClass
Örnek
Şöyle yaparız.
"%JAVA_HOME%\jre\bin\java.exe" -classpath bind MyMainClass
Örnek - Birden fazla dizin
Windows'ta tek tırnak ile şöyle yaparız. Dizinler ; karakteri ile ayrılır
java -verbose -classpath '../lib;.' bt_sim <args>
Linux'ta dizinler : karakteri ile ayrılır.

Bu seçeneği kullanmak yerine CLASSPATH ortam değişkenini kullanmak daha iyi.
bash$ export CLASSPATH="path/to/jars/directory1:path/tojars/directory2"
bash$ javac MyMainClass.java
Örnek - wildcard
Açıklaması şöyle.
Class path entries can contain the basename wildcard character *, which is considered equivalent to specifying a list of all the files in the directory with the extension .jar or .JAR. For example, the class path entry foo/* specifies all JAR files in the directory named foo. A classpath entry consisting simply of * expands to a list of all the jar files in the current directory.
Bir dizindeki tüm jar'ları dahil etmek için şöyle yaparız.
java -cp /home/acelya/*: MyMainClass
-de seçeneği
Açıklaması şöyle. disable assertions anlamına gelir.
-da[:<packagename>...|:<classname>]
    -disableassertions[:<packagename>...|:<classname>]
                  disable assertions with specified granularity
Assertleri kapatır.

-ea seçeneği
Açıklaması şöyle enables assertions anlamına gelir.
-ea[:<packagename>...|:<classname>]
    -enableassertions[:<packagename>...|:<classname>]
                  enable assertions with specified granularity
Kod içindeki assertlerin çalışması için gerekir. Uzun hali -enableassertions seçeneğidir. Kod derleyici tarafından şu hale getirilir.
if (!cond)
    throw new AssertionError();
Eğer assert için mesaj kullanılırsa
assert d != null : "d is null";
Kod derleyici tarafından şu hale getirilir.
if ($assertionsEnabled && !(Expression1))
    throw new AssertionError(Expression2);
-D seçeneği
Parametre Geçme Seçenekleri yazısına taşıdım

-jar seçeneği - Executable Jar çalıştırmak
Açıklaması şöyle.
Usage: java [-options] class [args...]
           (to execute a class)
   or  java [-options] -jar jarfile [args...]
           (to execute a jar file)
jar dosyasında Manifest varsa şöyle ve bu dosyada Main-Class satırı varsa şöyle yaparız.
java -jar path/to/jar/file
Eğer Manifest dosyası yoksa başlangıç sınıfını vermek gerekir.
java -cp path/to/jar/file MainClass
Elimizde şöyle bir dizin yapısı olsun
jar_root/
├── executable.jar
├── folder1/
    └── required_file1.txt

├── folder2/
    └── required_file2.txt

├── other_folder/
   └── ...
└── other_file.txt
executable.jar dosyasını çalıştırınca folder1/required_file1.txt dosyasını okumak istiyor olsun. Bu durumda harici bir dosya okuduğumuz için jar dosyası şöyle çalıştırılır. Önce jar'ın olduğu dizine gideriz. Sonra -jar seçeneği ile executable jar'ı çalıştırırız.
cd /path/to/jar_root/ 
java -jar executable.jar <options>
jar içindeki java kodu dosyayı muhtemelen şöyle açıyordur.
File file = new File("folder1", "required_file1")
-javaagent seçeneği
Dynamic Agent Loading yeteneği Java 21 ile deprecate ediliyor.

Örnek
Şöyle yaparız.
java -javaagent:agent.jar -jar myApp.jar
-help seçeneği
Şöyle yaparız.
$ java -help
Usage: java [options] <mainclass> [args...]
           (to execute a class)
   or  java [options] -jar <jarfile> [args...]
           (to execute a jar file)
   or  java [options] -m <module>[/<mainclass>] [args...]
       java [options] --module <module>[/<mainclass>] [args...]
           (to execute the main class in a module)
   or  java [options] <sourcefile> [args]
           (to execute a single source-file program)
--illegal-access seçeneği
Açıklaması şöyle
Since Java 16, the --illegal-access flag is set to deny by default, resulting in some calls (mainly related to reflection) being treated as illegal and throwing a beautiful java.lang.reflect.InaccessibleObjectException. In our case, we found out that the libraries Kryo (through Chill) and Aeron use low-level JDK APIs and now trigger illegal access exceptions.

We immediately spotted this issue with our test battery and fixed it by simply allowing access to these internal APIs with a set of extra parameters passed at runtime — --add-opens {package}=ALL-UNNAMED. After a session of trial and error, we came up with the correct list of packages to open. To go further on this topic we recommend looking into JEP 396 and JEP 403.
-m seçeneği
Çalıştırılacak ana sınıfı beliritr.
--module modulename[/mainclass] veya -m module[/mainclass] şeklindedir.
Örnek
Şöyle yaparız.
java --module-path mods    -m     com.test/com.test.HelloWorld
                   ^               ^         ^
           module directory  module name   main class
--module-path veya -p seçeneği
-p ile aynıdır. Açıklaması şöyle. Yani --module-path modulepath veya -p modulepath şeklindedir.
Searches for directories from a semicolon-separated (;) list of directories. Each directory is a directory of modules.
Örnek
Şöyle yaparız.
java --module-path mymods -m com.test/com.test.HelloWorld
Örnek
Moduler jar dosyasındaki modülleri listelemek için şöyle yaparız.
java -p yourModular.jar --list-modules
-noverify seçeneği
Açıklaması şöyle. Bytecode'un değişmediğini değil, zarar vermeyeceğini doğrulamaya çalışır.
When a class loader presents the bytecodes of a newly loaded Java platform class to the virtual machine, these bytecodes are first inspected by a verifier. The verifier checks that the instructions cannot perform actions that are obviously damaging. All classes except for system classes are verified. You can, however, deactivate verification with the undocumented -noverify option.
-server seçeneği
Açıklaması şöyle
-server       to select the "server" VM
                  The default VM is server.
--source seçeneği
java komutu normalde derlenmiş .class dosyalarını çalıştırır. Java 11 ile tek dosyadan oluşan (dosya içinde birden fazla class kodu olabilir) kaynak kodu çalıştırmak için de kullanılabiliyor.

-X seçeneği
-X Seçenekleri yazısına taşıdım.

-XX seçenekleri
XX Seçenekleri yazısına taşıdım.

-verbose seçeneği
Açıklaması şöyle
-verbose:[class|gc|jni]
                  enable verbose output
Daha detaylı çıktı üretir. Şöyle yaparız.
java -verbose ...
-version seçeneği
-version seçeneği yazısına taşıdım.