我正在为学校做一个模拟网络(特别是传输层、网络层和数据链路层)的作业。由于与规则相关的原因,我不能直接共享我的大部分代码,但这不应该影响我的问题。我们需要通过使用 shell 脚本创建 node 对象的多个副本(在我的实现中每个副本使用一个用户线程)来运行程序,然后在没有进一步输入的情况下执行。我选择使用 Java,因为我们被告知任何语言都可以用于该项目,而且我不知道我们必须在其上运行它的 Unix 服务器的用户限制(在下面发布)。
这是
ulimit -a
的打印输出
{} ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 1030869
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) 432000
max user processes (-u) 128
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
例如,这是评分者可以使用的一个示例场景:
node 0 120 5 "Message Sent Over" 30 1 2 &
node 1 120 1 0 2 &
node 2 120 2 0 1 3 4 &
node 3 120 3 2 4 6 &
node 4 120 4 2 3 5 &
node 5 120 5 4 6 &
node 6 120 6 3 5 &
(如果重要,参数格式为 node {id} {duration} {target "Message" sendTime} {neighbors})
现在,在我的 PC 上执行时没有任何错误(使用 IntelliJ 复合测试用例和通过 CMD 运行)。但是,在学校 Unix 服务器上运行时(要求)我在 ~3 个节点后收到以下错误:
{} Error occurred during initialization of VM
java.lang.OutOfMemoryError: unable to create new native thread
从我读到的内容来看,这意味着我已经达到线程限制。在我的机器上这不是问题,我们被告知创建太多线程可能是个问题,但 java 可用于该项目。运行命令
ps huH p <PID_OF_U_PROCESS> | wc -l
产生 ~33(我相信这是该进程的线程数)。在我的 PC 上,每次执行最多使用 11 个线程(使用 VisualVM 发现,除了其中一个线程外,所有线程都是守护线程),虽然比我想要的要多,但可以让我执行我们需要考虑的最艰巨的测试用例。我也没有在整个执行过程中创建额外的线程。该程序始终只使用一个用户线程。
有什么方法可以减少我的罐子使用的线程数吗?只创建了一个用户线程,鉴于学校服务器上对我的用户设置的限制(坦率地说低得离谱),我无法更改,因此生成多个 JVM 似乎正在扼杀我运行代码的能力。
编辑:服务器运行Java 1.8,具体为:
java version "1.8.0_341"
Java(TM) SE Runtime Environment (build 1.8.0_341-b10)
Java HotSpot(TM) 64-Bit Server VM (build 25.341-b10, mixed mode)
Edit2:澄清一下,我不是在创建新线程。我的 jar 在执行时以顺序方式运行,从不分叉或创建任何额外的线程。除了用户线程之外的所有线程都是由 Java 创建的,与我的代码或我的操作无关。我正在寻求限制这些线程,因为它们迫使我达到用户限制。
Edit3:我可以分享一些非实现代码(对其他学生没有帮助的东西,但应该有助于理解程序的工作原理)
public static void main(String[] args)
{
node thisNode = new node(args);
}
//Node constructor
private node(String[] args) //Class constructor
{
try
{
setArgs(args); //Set args appropriately
network = new Network(id, neighbors); //Instantiate network with node id
datalink = new DataLink(network, id); //Instantiate datalink with node id and network instance
network.setDataLink(datalink); //Set network's datalink variable to instance of datalink
transport = new Transport(id, network, start, message, destination); //Instantiate transport with node id and network instance
network.setTransport(transport); //Set network's transport variable to instance of transport
int startingTime = lifetime;
for (;lifetime != 0; lifetime--) //Countdown lifetime to 0
{
datalink.receiveFromChannel(); //Tell datalink layer to read from channels
transport.sendMessage(); //Tell transport layer to send messages (if proper time)
if ((startingTime - lifetime) % 10 == 0)
{
network.route(startingTime - lifetime); //Tell network layer to route according to current time
}
Thread.sleep(1000); //Sleep 1 second
}
transport.outputAllReceived(); //Output all messages with this node as a destination
}
catch (Exception e)
{
//System.out.println(e + " in node");
}
}