提交 50b5f52a authored 作者: Thomas Mueller's avatar Thomas Mueller

Less heap memory is needed when multiple databases are open at the same time.

上级 53e6320d
...@@ -17,6 +17,7 @@ import org.h2.message.Trace; ...@@ -17,6 +17,7 @@ import org.h2.message.Trace;
import org.h2.message.TraceObject; import org.h2.message.TraceObject;
import org.h2.result.LocalResult; import org.h2.result.LocalResult;
import org.h2.result.ResultInterface; import org.h2.result.ResultInterface;
import org.h2.util.MemoryUtils;
import org.h2.util.ObjectArray; import org.h2.util.ObjectArray;
/** /**
...@@ -193,7 +194,7 @@ public abstract class Command implements CommandInterface { ...@@ -193,7 +194,7 @@ public abstract class Command implements CommandInterface {
public int executeUpdate() throws SQLException { public int executeUpdate() throws SQLException {
long start = startTime = System.currentTimeMillis(); long start = startTime = System.currentTimeMillis();
Database database = session.getDatabase(); Database database = session.getDatabase();
database.allocateReserveMemory(); MemoryUtils.allocateReserveMemory();
Object sync = database.isMultiThreaded() ? (Object) session : (Object) database; Object sync = database.isMultiThreaded() ? (Object) session : (Object) database;
session.waitIfExclusiveModeEnabled(); session.waitIfExclusiveModeEnabled();
synchronized (sync) { synchronized (sync) {
...@@ -205,7 +206,7 @@ public abstract class Command implements CommandInterface { ...@@ -205,7 +206,7 @@ public abstract class Command implements CommandInterface {
try { try {
return update(); return update();
} catch (OutOfMemoryError e) { } catch (OutOfMemoryError e) {
database.freeReserveMemory(); MemoryUtils.freeReserveMemory();
throw Message.convert(e); throw Message.convert(e);
} catch (SQLException e) { } catch (SQLException e) {
if (e.getErrorCode() == ErrorCode.CONCURRENT_UPDATE_1) { if (e.getErrorCode() == ErrorCode.CONCURRENT_UPDATE_1) {
......
...@@ -154,13 +154,12 @@ public class Database implements DataHandler { ...@@ -154,13 +154,12 @@ public class Database implements DataHandler {
private boolean multiVersion; private boolean multiVersion;
private DatabaseCloser closeOnExit; private DatabaseCloser closeOnExit;
private Mode mode = Mode.getInstance(Mode.REGULAR); private Mode mode = Mode.getInstance(Mode.REGULAR);
// TODO change in version 1.1 // TODO change in version 1.2
private boolean multiThreaded; private boolean multiThreaded;
private int maxOperationMemory = SysProperties.DEFAULT_MAX_OPERATION_MEMORY; private int maxOperationMemory = SysProperties.DEFAULT_MAX_OPERATION_MEMORY;
private boolean lobFilesInDirectories = SysProperties.LOB_FILES_IN_DIRECTORIES; private boolean lobFilesInDirectories = SysProperties.LOB_FILES_IN_DIRECTORIES;
private SmallLRUCache lobFileListCache = new SmallLRUCache(128); private SmallLRUCache lobFileListCache = new SmallLRUCache(128);
private boolean autoServerMode; private boolean autoServerMode;
private Object reserveMemory;
private Server server; private Server server;
private HashMap linkConnections; private HashMap linkConnections;
private TempFileDeleter tempFileDeleter = TempFileDeleter.getInstance(); private TempFileDeleter tempFileDeleter = TempFileDeleter.getInstance();
...@@ -2022,7 +2021,8 @@ public class Database implements DataHandler { ...@@ -2022,7 +2021,8 @@ public class Database implements DataHandler {
} }
public void setMultiThreaded(boolean multiThreaded) throws SQLException { public void setMultiThreaded(boolean multiThreaded) throws SQLException {
if (multiThreaded && multiVersion) { if (multiThreaded && multiVersion && this.multiThreaded != multiThreaded) {
// currently the combination of MVCC and MULTI_THREADED is not supported
throw Message.getSQLException(ErrorCode.CANNOT_CHANGE_SETTING_WHEN_OPEN_1, "MVCC & MULTI_THREADED"); throw Message.getSQLException(ErrorCode.CANNOT_CHANGE_SETTING_WHEN_OPEN_1, "MVCC & MULTI_THREADED");
} }
this.multiThreaded = multiThreaded; this.multiThreaded = multiThreaded;
...@@ -2061,23 +2061,6 @@ public class Database implements DataHandler { ...@@ -2061,23 +2061,6 @@ public class Database implements DataHandler {
return meta.isLockedExclusively(); return meta.isLockedExclusively();
} }
/**
* Allocate a little main memory that is freed up when if no memory is
* available, so that rolling back a large transaction is easier.
*/
public void allocateReserveMemory() {
if (reserveMemory == null) {
reserveMemory = new byte[SysProperties.RESERVE_MEMORY];
}
}
/**
* Free up the reserve memory.
*/
public void freeReserveMemory() {
reserveMemory = null;
}
/** /**
* Open a new connection or get an existing connection to another database. * Open a new connection or get an existing connection to another database.
* *
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
*/ */
package org.h2.util; package org.h2.util;
import org.h2.constant.SysProperties;
/** /**
* This is a utility class with functions to measure the free and used memory. * This is a utility class with functions to measure the free and used memory.
*/ */
...@@ -14,6 +16,7 @@ public class MemoryUtils { ...@@ -14,6 +16,7 @@ public class MemoryUtils {
private static long lastGC; private static long lastGC;
private static final int GC_DELAY = 50; private static final int GC_DELAY = 50;
private static final int MAX_GC = 8; private static final int MAX_GC = 8;
private static volatile byte[] reserveMemory;
private MemoryUtils() { private MemoryUtils() {
// utility class // utility class
...@@ -60,4 +63,21 @@ public class MemoryUtils { ...@@ -60,4 +63,21 @@ public class MemoryUtils {
} }
} }
/**
* Allocate a little main memory that is freed up when if no memory is
* available, so that rolling back a large transaction is easier.
*/
public static void allocateReserveMemory() {
if (reserveMemory == null) {
reserveMemory = new byte[SysProperties.RESERVE_MEMORY];
}
}
/**
* Free up the reserve memory.
*/
public static void freeReserveMemory() {
reserveMemory = null;
}
} }
...@@ -37,6 +37,9 @@ public class TestOutOfMemory extends TestBase { ...@@ -37,6 +37,9 @@ public class TestOutOfMemory extends TestBase {
if (config.memory || config.mvcc) { if (config.memory || config.mvcc) {
return; return;
} }
for (int i = 0; i < 5; i++) {
System.gc();
}
deleteDb("outOfMemory"); deleteDb("outOfMemory");
Connection conn = getConnection("outOfMemory"); Connection conn = getConnection("outOfMemory");
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论