- Шаг первый: смоделировать многопоточную среду с 600 потоками.
- Шаг второй: каждую секунду запускать два новых потока, которые читают большой файл через java.nio.channels.FileChannel.
- Шаг третий: через 10 секунд автоматически завершиться и позвольте GC выполнить очистку.
- Согласно отчету NMT, вы обнаружите, что учет JVM не показывает использование такого большого количества памяти.
- Из информации Linux pmap и smaps вы увидите, что каждый блок размером 64 МБ в неосновных регионах арены в физической памяти задето около 8 МБ. Если вы попытаетесь прочитать двоичные данные из памяти, вы обнаружите, что все это содержимое вашего файла.
Кстати, версия JDK, которую я использовал, — 21-openjdk, а версия glibc — 2.39.
При каждом чтении файла процесс вызывает malloc для запроса памяти вне кучи, и после поток умирает, поток GC инициирует свободную операцию. Таким образом, в дампе JVM вы можете наблюдать, что все объекты, включая DirectBuffer вне кучи, уничтожаются по порядку.
Мои основные вопросы двоякие: почему этот параметр влияет на падение использования памяти? Кроме того, когда для него установлено значение 50 МБ, даже до теоретического достижения порога в 50 МБ, glibc также возвращает память из неосновной арены в ОС. Похоже, что после установки этого параметра свободное поведение glibc изменилось?
Добавить: это параметр времени выполнения JVM, и он простой.
-Xms6g -Xmx6g -XX:MaxDirectMemorySize=5g -XX:+AlwaysPreTouch -XX:+UseG1GC -Xlog:gc:file=gc.log:time,uptime,level,tags:filecount=5,filesize=100M*
import java.io.RandomAccessFile;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;
public class FileRead1 {
private static volatile boolean stop = false;
public static void main(String[] args) throws InterruptedException {
liveThreadLoopWithoutMemory();
int count = 0;
while (true) {
if (count > (Integer.MAX_VALUE -1) ) {
break;
}
count++;
try {
for (int i = 0; i < 2; i++) {
newThread();
}
for (int i = 0; i < 5; i++) {
Thread.sleep(1000L);
}
} catch (InterruptedException e) {
}
}
stop = true;
while (true) {
for (int i = 0; i < 5; i++) {
Thread.sleep(1000L);
}
}
}
private static void liveThreadLoopWithoutMemory() {
for (int i = 0; i < 600; i++) {
new Thread(() -> {
while (true) {
try {
Thread.sleep(100L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
if (stop) {
break;
}
}
}).start();
}
}
private static void newThread() {
Thread thread = new Thread(new Runnable() {
private final List strings = new ArrayList();
@Override
public void run() {
test(strings, "test.txt", "UTF-8", false);
strings.clear();
}
});
thread.setDaemon(true);
thread.start();
}
private static void test(List strings, String src, String encoding, boolean hasTitle) {
test1(strings, src, encoding, hasTitle);
}
private static void test1(List strings, String src, String encoding, boolean hasTitle) {
test2(strings, src, encoding, hasTitle);
}
private static void test2(List strings, String src, String encoding, boolean hasTitle) {
test3(strings, src, encoding, hasTitle);
}
private static void test3(List strings, String src, String encoding, boolean hasTitle) {
test4(strings, src, encoding, hasTitle);
}
private static void test4(List strings, String src, String encoding, boolean hasTitle) {
test5(strings, src, encoding, hasTitle);
}
private static void test5(List strings, String src, String encoding, boolean hasTitle) {
test6(strings, src, encoding, hasTitle);
}
private static void test6(List strings, String src, String encoding, boolean hasTitle) {
test7(strings, src, encoding, hasTitle);
}
private static void test7(List strings, String src, String encoding, boolean hasTitle) {
test8(strings, src, encoding, hasTitle);
}
private static void test8(List strings, String src, String encoding, boolean hasTitle) {
test9(strings, src, encoding, hasTitle);
}
private static void test9(List strings, String src, String encoding, boolean hasTitle) {
test10(strings, src, encoding, hasTitle);
}
private static void test10(List strings, String src, String encoding, boolean hasTitle) {
new TaskReadFile() {
@Override
public void process(String str) {
super.process(str + "swk");
}
}.readFile(strings, src, encoding, hasTitle);
}
static class TaskReadFile implements ReadFileInterface {
private final List stringList = new ArrayList();
@Override
public void process(String str) {
stringList.add(str + "123");
}
@Override
public void clear() {
stringList.clear();
}
}
interface ReadFileInterface {
void process(String str);
void clear();
default void readFile(List strings, String src, String encoding, boolean hasTitle) {
int readLimit = 8 * 1024 * 1024;
int startIndex = 0;
try (RandomAccessFile raf = new RandomAccessFile(src, "r");) {
FileChannel channel = raf.getChannel();
ByteBuffer rbuf = ByteBuffer.allocate(readLimit);
synchronized (rbuf) {
channel.position(startIndex);
byte[] temp = new byte[0];
int LF = 10;
long lineCount = 0;
while (channel.read(rbuf) != -1) {
int position = rbuf.position();
byte[] rbyte = new byte[position];
rbuf.flip();
rbuf.get(rbyte);
int startnum = 0;
for (int i = 0; i < rbyte.length; i++) {
if (rbyte == LF) {
if (channel.position() == startIndex) {
startnum = i + 1;
} else {
if (hasTitle && 0 == lineCount) {
startnum = i + 1;
lineCount++;
continue;
}
int lineLen = i - startnum + 1;
byte[] line = new byte[temp.length + lineLen];
System.arraycopy(temp, 0, line, 0, temp.length);
System.arraycopy(rbyte, startnum, line, temp.length, lineLen);
startnum = i + 1;
temp = new byte[0];
String str = trimEndingCRLF(line, encoding);
strings.add(str);
process(str);
}
}
}
if (startnum < rbyte.length) {
byte[] temp2 = new byte[temp.length + rbyte.length - startnum];
System.arraycopy(temp, 0, temp2, 0, temp.length);
System.arraycopy(rbyte, startnum, temp2, temp.length, rbyte.length - startnum);
temp = temp2;
}
rbuf.clear();
}
}
rbuf.clear();
try {
Thread.sleep(10000L);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
clear();
} catch (Exception e) {
throw new RuntimeException();
}
}
default String trimEndingCRLF(byte[] line, String encoding) throws UnsupportedEncodingException {
if (line.length != 0 && line[0] != 10) {
int lastIdx = line.length - 1;
if (line[lastIdx] != 10) {
++lastIdx;
} else if (line[lastIdx - 1] == 13) {
--lastIdx;
}
return new String(line, 0, lastIdx, encoding);
} else {
return "";
}
}
}
}
```java
Подробнее здесь: https://stackoverflow.com/questions/798 ... ing-system
Мобильная версия