2009-07-14 22 views
65

Trên hệ thống của tôi, tôi không thể chạy một ứng dụng Java đơn giản bắt đầu quá trình. Tôi không biết cách giải quyết.Cách giải quyết "java.io.IOException: error = 12, Không thể cấp phát bộ nhớ" gọi Runtime # exec()?

Bạn có thể cho tôi một số gợi ý cách giải quyết không?

Chương trình này là:

[[email protected] sisma-acquirer]# cat prova.java 
import java.io.IOException; 

public class prova { 

    public static void main(String[] args) throws IOException { 
     Runtime.getRuntime().exec("ls"); 
    } 

} 

Kết quả là:

[[email protected] sisma-acquirer]# javac prova.java && java -cp . prova 
Exception in thread "main" java.io.IOException: Cannot run program "ls": java.io.IOException: error=12, Cannot allocate memory 
     at java.lang.ProcessBuilder.start(ProcessBuilder.java:474) 
     at java.lang.Runtime.exec(Runtime.java:610) 
     at java.lang.Runtime.exec(Runtime.java:448) 
     at java.lang.Runtime.exec(Runtime.java:345) 
     at prova.main(prova.java:6) 
Caused by: java.io.IOException: java.io.IOException: error=12, Cannot allocate memory 
     at java.lang.UNIXProcess.<init>(UNIXProcess.java:164) 
     at java.lang.ProcessImpl.start(ProcessImpl.java:81) 
     at java.lang.ProcessBuilder.start(ProcessBuilder.java:467) 
     ... 4 more 

Cấu hình của hệ thống:

[[email protected] sisma-acquirer]# java -version 
java version "1.6.0_0" 
OpenJDK Runtime Environment (IcedTea6 1.5) (fedora-18.b16.fc10-i386) 
OpenJDK Client VM (build 14.0-b15, mixed mode) 
[[email protected] sisma-acquirer]# cat /etc/fedora-release 
Fedora release 10 (Cambridge) 

EDIT: Giải pháp Điều này giải quyết vấn đề của tôi, tôi không biết chính xác lý do:

vang 0>/proc/sys/vm/overcommit_memory

Up-phiếu cho là người có thể giải thích :)

thông tin bổ sung, đầu ra:

top - 13:35:38 up 40 min, 2 users, load average: 0.43, 0.19, 0.12 
Tasks: 129 total, 1 running, 128 sleeping, 0 stopped, 0 zombie 
Cpu(s): 1.5%us, 0.5%sy, 0.0%ni, 94.8%id, 3.2%wa, 0.0%hi, 0.0%si, 0.0%st 
Mem: 1033456k total, 587672k used, 445784k free, 51672k buffers 
Swap: 2031608k total,  0k used, 2031608k free, 188108k cached 

thông tin bổ sung, đầu ra miễn phí:

[[email protected] sisma-acquirer]# free 
      total  used  free  shared buffers  cached 
Mem:  1033456  588548  444908   0  51704  188292 
-/+ buffers/cache:  348552  684904 
Swap:  2031608   0 2031608 
+0

Đó là lỗi trong phiên bản Linux hoặc bạn có một số vấn đề đặc quyền. Bạn có thể nhìn vào UnixProcess: 164 trong nguồn để tìm hiểu những gì nó cố gắng phân bổ. – akarnokd

+1

Bạn luôn có thể thử mặt trời jdk – wds

+0

Tôi đã đăng liên kết tới một thư viện miễn phí giải quyết được vấn đề của bạn nhưng một người kiểm duyệt đã xóa câu trả lời của tôi mà không cần giải thích. Vì lợi ích của cộng đồng, tôi cung cấp cho nó một thử như bình luận: vấn đề bộ nhớ của bạn được giải quyết bởi Yajsw mà trên Linux sử dụng các cuộc gọi đến một thư viện C cho quá trình tạo ra. Đọc về nó ở đây: http://sourceforge.net/projects/yajsw/forums/forum/810311/topic/4423982 – kongo09

Trả lời

16

Cấu hình bộ nhớ của máy của bạn là gì? ví dụ. nếu bạn chạy top, bạn có bao nhiêu bộ nhớ miễn phí?

tôi nghi ngờ UnixProcess thực hiện một fork() và nó chỉ đơn giản là không nhận được đủ bộ nhớ từ hệ điều hành (nếu bộ nhớ phục vụ, nó sẽ fork() lặp quá trình này và sau đó exec() để chạy các ls trong quá trình bộ nhớ mới, và nó không nhận như xa như vậy)

EDIT: Re. giải pháp overcommit của bạn, nó cho phép overcommitting bộ nhớ hệ thống, có thể cho phép các quy trình để phân bổ (nhưng không sử dụng) nhiều bộ nhớ hơn là thực sự có sẵn. Vì vậy, tôi đoán rằng các fork() sao chép bộ nhớ quá trình Java như được thảo luận trong các ý kiến ​​dưới đây. Tất nhiên bạn không sử dụng bộ nhớ vì 'ls' thay thế quá trình Java trùng lặp.

+0

Tôi đã từng đọc rằng cuộc gọi fork() thực sự sao chép toàn bộ bộ nhớ của tiến trình đang chạy. Nó vẫn còn đúng không? Nếu bạn có một chương trình java với bộ nhớ 1,2 GB và tổng cộng 2GB, tôi đoán nó sẽ thất bại? – akarnokd

+2

Có. Tôi sẽ đề cập đến điều này, nhưng tôi mơ hồ nhớ rằng các hệ điều hành hiện đại sẽ thực hiện copy-on-write cho các trang bộ nhớ, vì vậy tôi không chắc chắn về điều này –

+0

Nếu cô ấy chạy ứng dụng với các thiết lập mặc định, nó không phải là một vấn đề với bộ nhớ dupe 64MB tôi đoán. – akarnokd

9

Runtime.getRuntime().exec phân bổ quá trình với cùng một lượng bộ nhớ như chính. Nếu bạn đã có bạn đống thiết lập để 1GB và cố gắng để exec sau đó nó sẽ phân bổ 1GB khác cho quá trình đó để chạy.

+2

Tôi gặp vấn đề này với Maven. Máy của tôi có bộ nhớ 1GB và nó đang chạy Hudson, Nexus và một quy trình Maven khác. Quá trình Maven bị lỗi vì chúng tôi đặt -Xms512m do nhầm lẫn trên MAVEN_OPTS. Sửa chữa nó để -Xms128m giải quyết nó. –

33

Đây là giải pháp nhưng bạn phải thiết lập:

echo 1 > /proc/sys/vm/overcommit_memory 
+24

Hãy coi chừng! Với overcommit_memory được đặt thành 1 mỗi malloc() sẽ thành công. Linux sẽ bắt đầu các quá trình giết chết ngẫu nhiên khi bạn hết bộ nhớ. http://www.win.tue.nl/~aeb/linux/lk/lk-9.html –

+0

Có thể hạn chế điều này cho mỗi quá trình, thay vì toàn hệ thống không? –

+1

Sử dụng giải pháp này trong phát triển trong hộp Vagrant. –

5

Nếu bạn nhìn vào nguồn gốc của java.lang.Runtime, bạn sẽ thấy exec cuối cùng gọi phương thức bảo vệ: execVM, có nghĩa là nó sử dụng Bộ nhớ ảo.Vì vậy, đối với hệ thống giống Unix, VM phụ thuộc vào lượng không gian hoán đổi + một số tỷ lệ bộ nhớ vật lý.

Câu trả lời của Michael đã giải quyết được vấn đề của bạn nhưng có thể (hoặc nói, cuối cùng) sẽ gây ra O.S. bế tắc trong vấn đề phân bổ bộ nhớ kể từ 1 cho O.S. ít cẩn thận về phân bổ bộ nhớ & 0 chỉ là đoán & rõ ràng là bạn may mắn rằng O.S. đoán bạn có thể có bộ nhớ THỜI GIAN NÀY. Lần tới? Hmm .....

Better cách tiếp cận là bạn thử nghiệm trường hợp của bạn & cung cấp cho một không gian hoán đổi tốt & đưa ra một tỷ lệ tốt hơn bộ nhớ vật lý sử dụng & giá trị thiết lập để 2 chứ không phải là 1 hoặc 0.

4

overcommit_memory

Kiểm soát quá mức bộ nhớ hệ thống, có thể cho phép các quy trình phân bổ bộ nhớ nhiều hơn (nhưng không sử dụng) nhiều hơn so với thực tế có sẵn.

0 - Xử lý quá tải quá mức. Rõ ràng các overcommits của không gian địa chỉ bị từ chối. Được sử dụng cho một hệ thống điển hình. Nó đảm bảo một phân bổ nghiêm trọng hoang dã không thành công trong khi cho phép overcommit để giảm sử dụng trao đổi. root được phép phân bổ bộ nhớ nhiều hơn một chút trong chế độ này. Đây là mặc định.

1 - Luôn ghi đè. Thích hợp cho một số ứng dụng khoa học.

2 - Đừng quá thừa. Tổng không gian địa chỉ cam kết cho hệ thống không được phép vượt quá swap cộng với phần trăm cấu hình (mặc định là 50) của RAM vật lý. Tùy thuộc vào tỷ lệ phần trăm bạn sử dụng, trong hầu hết các trường hợp, điều này có nghĩa là một quá trình sẽ không bị giết trong khi cố gắng sử dụng bộ nhớ đã cấp phát nhưng sẽ nhận được lỗi khi cấp phát bộ nhớ cho phù hợp.

4

Bạn có thể sử dụng trình bao bọc Tanuki để tạo ra một quá trình với trứng giống POSIX thay vì ngã ba. http://wrapper.tanukisoftware.com/doc/english/child-exec.html

The WrapperManager.exec() function is an alternative to the Java-Runtime.exec() which has the disadvantage to use the fork() method, which can become on some platforms very memory expensive to create a new process.

+0

Bao bì Tanuki khá ấn tượng. Thật không may, 'WrapperManager' là một phần của phiên bản chuyên nghiệp, mà là khá tốn kém nếu đây là điều duy nhất bạn cần. Bạn có biết về bất kỳ giải pháp thay thế miễn phí nào không? – kongo09

+0

@ kongo09 Nó có sẵn như là một phần của phiên bản cộng đồng miễn phí (GPLv2). Bạn thậm chí có thể tải xuống nguồn và sử dụng nó trong các sản phẩm GPL. –

+0

Tôi không nghĩ rằng đây là một phần của ấn bản cộng đồng. Nếu bạn thử nghiệm nhanh, bạn sẽ nhận được ngoại lệ sau: org.tanukisoftware.wrapper.WrapperLicenseError: "Yêu cầu phiên bản chuyên nghiệp.' – kongo09

8

tôi giải quyết này sử dụng JNA: https://github.com/twall/jna

import com.sun.jna.Library; 
import com.sun.jna.Native; 
import com.sun.jna.Platform; 

public class prova { 

    private interface CLibrary extends Library { 
     CLibrary INSTANCE = (CLibrary) Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"), CLibrary.class); 
     int system(String cmd); 
    } 

    private static int exec(String command) { 
     return CLibrary.INSTANCE.system(command); 
    } 

    public static void main(String[] args) { 
     exec("ls"); 
    } 
} 
9

này được giải quyết trong phiên bản Java 1.6.0_23 và trở lên.

Xem thêm chi tiết tại http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7034935

+0

Bất kỳ ý tưởng nào nếu nó áp dụng cho OpenJDK hoặc các JVM không phải Sun tương đương ? –

+0

Tôi không nhận được vấn đề này sau khi nâng cấp lên 1.6.0_37-b06 .. Vẫn còn nhầm lẫn về sửa lỗi .. Vì vậy, bao nhiêu bộ nhớ jvm phân bổ cho 'Runtime.exec'? –

+0

Điểm tuyệt vời. Việc nâng cấp JVM sẽ khắc phục vấn đề khi họ sử dụng một cuộc gọi hệ thống khác (nhẹ hơn). – neesh

4

Như lạ như thế này nghe có vẻ, một công việc xung quanh là giảm dung lượng bộ nhớ được phân bổ cho các JVM. Vì fork() sao chép quá trình và bộ nhớ của nó, nếu quá trình JVM của bạn không thực sự cần nhiều bộ nhớ như được cấp phát thông qua -Xmx, việc cấp phát bộ nhớ cho git sẽ hoạt động.

Tất nhiên bạn có thể thử các giải pháp khác được đề cập ở đây (như cam kết quá mức hoặc nâng cấp lên JVM có bản sửa lỗi). Bạn có thể thử giảm bộ nhớ nếu bạn đang tuyệt vọng cho một giải pháp mà giữ tất cả các phần mềm còn nguyên vẹn mà không có tác động môi trường. Cũng nên nhớ rằng việc giảm -Xmx mạnh có thể gây ra OOM. Tôi khuyên bạn nên nâng cấp JDK như một giải pháp ổn định lâu dài.

0

Việc giết đơn giản có hiệu quả đối với tôi.

Do

free -m

để kiểm tra dung lượng bộ nhớ có sẵn.

Giết một số công việc không cần thiết.

Các vấn đề liên quan