大きな 1D 配列 (~1G) の要素の合計を計算する必要がある JNA アプリケーションがあります。JNA Resource.Rlimit クラスを使用すると、次のスニペットに示すようにリソース制限を増やすことができます。
final Resource.Rlimit limit = new Resource.Rlimit();
limit.rlim_cur = 1024L * 1024L * 1024L;
limit.rlim_max = 2 * 1024L * 1024L * 1024L;
ただし、これは、大きな配列を割り当てるメソッド内でスタック サイズが設定されている場合にのみ機能します。したがって、以下のコードを実行すると、メモリ不足の例外はありません。
package com.jnaapps;
import com.sun.jna.Library;
import com.sun.jna.Pointer;
import com.sun.jna.Native;
import com.sun.jna.Memory;
import com.sun.jna.platform.unix.LibCAPI;
import com.sun.jna.platform.unix.Resource;
public class Main {
public interface CLibrary extends LibCAPI, Library {
CLibrary INSTANCE = (CLibrary) Native.load("c", CLibrary.class);
}
public interface NativeClass extends Library {
NativeClass INSTANCE = (NativeClass)Native.load("nativemethods", NativeClass.class);
double sumOfArray1d(final Pointer values, long numberOfValues);
}
public static void main(String[] args) {
Test0();
}
public static void Test0() {
final Resource.Rlimit limit = new Resource.Rlimit();
limit.rlim_cur = 1024L * 1024L * 1024L;
limit.rlim_max = 2 * 1024L * 1024L * 1024L;
int err = CLibrary.INSTANCE.setrlimit(Resource.RLIMIT_STACK, limit);
if (err != 0) {
int lastError = Native.getLastError();
System.out.println("An exception occurred while setting RLimit: " +
lastError);
}
NativeClass clib = NativeClass.INSTANCE;
long dim = 10000L * 10000L;
final Pointer bigVector = new Memory(dim*Native.getNativeSize(Double.TYPE));
for (long i=0; i<dim; ++i) {
bigVector.setDouble(i*Native.getNativeSize(Double.TYPE), 3.5e-6);
}
double total = clib.sumOfArray1d(bigVector, dim);
System.out.println("Sum of elements in big vector = " + total);
}
public static void Test1() {
NativeClass clib = NativeClass.INSTANCE;
long dim = 10000L * 10000L;
final Pointer bigVector = new Memory(dim*Native.getNativeSize(Double.TYPE));
for (long i=0; i<dim; ++i) {
bigVector.setDouble(i*Native.getNativeSize(Double.TYPE), 3.5e-6);
}
double total = clib.sumOfArray1d(bigVector, dim);
System.out.println("Sum of elements in big vector = " + total);
}
}
しかし、リソース制限が main() 内で設定され、メソッド Test1() が呼び出されると、プログラムがクラッシュします。
public static void main(String[] args) {
final Resource.Rlimit limit = new Resource.Rlimit();
limit.rlim_cur = 1024L * 1024L * 1024L;
limit.rlim_max = 2 * 1024L * 1024L * 1024L;
int err = CLibrary.INSTANCE.setrlimit(Resource.RLIMIT_STACK, limit);
if (err != 0) {
int lastError = Native.getLastError();
System.out.println("An exception occurred while setting RLimit: " +
lastError);
}
Test1();
}
Test1() を呼び出す前に main() のスタック サイズを増やすことができないのはなぜですか。このプロジェクトは、8GB RAM を搭載した Ubuntu 16.04 amdx86-64 上の IntelliJ Idea (コミュニティ バージョン 2019.3) で作成されました。