新聞中心
無論是Android亦或者Java中或多或少需要調用底層的一些命令,執(zhí)行一些參數(shù);

在石拐等地區(qū),都構建了全面的區(qū)域性戰(zhàn)略布局,加強發(fā)展的系統(tǒng)性、市場前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務理念,為客戶提供做網(wǎng)站、成都做網(wǎng)站 網(wǎng)站設計制作定制網(wǎng)站,公司網(wǎng)站建設,企業(yè)網(wǎng)站建設,品牌網(wǎng)站設計,成都全網(wǎng)營銷推廣,外貿(mào)營銷網(wǎng)站建設,石拐網(wǎng)站建設費用合理。
此時我們需要用到Java的process來創(chuàng)建一個子進程,之所以是子進程是因為此進程依賴于發(fā)起創(chuàng)建請求的進程,如果發(fā)起者被Kill那個子進程也將Kill。
對于Process相信使用過的朋友一定不會陌生,它具有如下特點:
1.創(chuàng)建簡單
2.控制難
3.容易導致無法創(chuàng)建子進程
4.如果是多線程那么很有可能造成內存溢出
以上現(xiàn)象如果你只是偶爾使用一次,創(chuàng)建一個進程或許你什么都沒有感覺到,但是如果你使用了多線程,進行了大量的創(chuàng)建,以上問題你都會遇到。
相關:http://blog.csdn.net/qiujuer/article/details/38142273,http://blog.csdn.net/qiujuer/article/details/38086071
這兩個星期一直在研究上面的問題,我要做的軟件是在Android中進行TraceRoute,由于手機不可能完全Root所以不能采用JNI來發(fā)送ICMP請求的方式,最終只能使用創(chuàng)建進程方式進行;具體實現(xiàn)思路是:使用PING命令來PING百度等地址,在PING命令中加入TTL,得到每一次的IP地址,當IP地址與目標IP地址符合時退出,并且還需要單獨PING一次每一跳的延遲和丟包。
單線程:PING 百度 TTL=1 =》 得到IP,PING IP 得到延遲丟包,改變TTL,進行下一次PING,直到所得到的IP與目標(百度)一樣時停止。按照上面的思路一次需要創(chuàng)建兩個子進程,一般到百度時TTL大約為12跳左右,所以就是2*12=24個子進程;如果是在單線程下簡單明了,但是速度慢,整個過程大約需要1分鐘左右。
多線程:同時發(fā)起3個線程進行3跳測試TTL=(1,2,3),測試完成后測試下一批數(shù)據(jù)TTL=(4,5,6),如果也是12跳的話,那么也是24個子進程,但是整體耗時將會為1/3.可見此時效率較高。
但是多線程需要考慮的是線程的同步問題,以及得到數(shù)據(jù)后的寫入問題,這些贊不談,只談進程問題。經(jīng)過我的測試假如現(xiàn)在測試100個網(wǎng)站的TraceRoute數(shù)據(jù),在上層控制一次測試4個網(wǎng)站,底層實現(xiàn)并發(fā)3個線程,此時在一定時間內將會同時存在3*4個進程。按照平均每個網(wǎng)站12跳來算:12*2*100=240個子進程,需要的子線程為12*100=120個。
這個時候問題來了,假如現(xiàn)在程序子進程不正常了,遇到了一個一定的問題導致進程無法執(zhí)行完成,此時你的現(xiàn)象是:一個子進程卡住,隨后創(chuàng)建的所有子進程都卡住。假如最上層線程做了任務時間限制,那么到時間后將會嘗試銷毀,但是你會發(fā)現(xiàn)無法銷毀,所持有的線程也不會銷毀。但是上層以為銷毀掉了,然后繼續(xù)進行下一批的數(shù)據(jù)測試,此時你的線程數(shù)量會逐漸增加,如果100任務下來你的線程或許會達到3*4*100=1200如果有前期沒有這樣的情況那個就是一半:600個線程左右,如果后期還有任務將會繼續(xù)增加但是卻永遠不會銷毀,但是我們知道JVM的內存是有限的,所以此時將會出現(xiàn)內存溢出。
以上就是我遇到的問題,我***改為了等待線程完全返回后再進行下一批數(shù)據(jù)測試,此時內存溢出是解決了,但是任務卻一直卡住在哪里了,永遠也不走。我就在想要解決這一的問題需要解決根本上的問題才行,經(jīng)過研究我發(fā)現(xiàn)在程序創(chuàng)建了子進程后JVM將會創(chuàng)建一個子進程管理線程:“ProcessManager”:
正常情況下該線程狀態(tài)為Native,但是如果創(chuàng)建大量子進程后有可能會出現(xiàn)此線程為Monitor狀態(tài),過一段時間后所有創(chuàng)建子進程的線程狀態(tài)也將會變?yōu)镸onitor狀態(tài),然后將一直死鎖,后面創(chuàng)建線程也是繼續(xù)死鎖,無法繼續(xù)。
通過查看ProcessManager源碼發(fā)現(xiàn),其中啟動了一個線程用于監(jiān)聽子進程狀態(tài),同時管理子進程,比如輸出消息以及關閉子進程等操作,具體如下
- /**
- * Copyright (C) 2007 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- package java.lang;
- import java.io.File;
- import java.io.FileDescriptor;
- import java.io.FileInputStream;
- import java.io.FileOutputStream;
- import java.io.IOException;
- import java.io.InputStream;
- import java.io.OutputStream;
- import java.lang.ref.ReferenceQueue;
- import java.lang.ref.WeakReference;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.Arrays;
- import java.util.logging.Logger;
- import java.util.logging.Level;
- /***
- * Manages child processes.
- *
- *
Harmony's native implementation (for comparison purposes):
- * http://tinyurl.com/3ytwuq
- */
- final class ProcessManager {
- /***
- * constant communicated from native code indicating that a
- * child died, but it was unable to determine the status
- */
- private static final int WAIT_STATUS_UNKNOWN = -1;
- /***
- * constant communicated from native code indicating that there
- * are currently no children to wait for
- */
- private static final int WAIT_STATUS_NO_CHILDREN = -2;
- /***
- * constant communicated from native code indicating that a wait()
- * call returned -1 and set an undocumented (and hence unexpected) errno
- */
- private static final int WAIT_STATUS_STRANGE_ERRNO = -3;
- /***
- * Initializes native static state.
- */
- static native void staticInitialize();
- static {
- staticInitialize();
- }
- /***
- * Map from pid to Process. We keep weak references to the Process objects
- * and clean up the entries when no more external references are left. The
- * process objects themselves don't require much memory, but file
- * descriptors (associated with stdin/out/err in this case) can be
- * a scarce resource.
- */
- private final Map
processReferences - = new HashMap
(); - /*** Keeps track of garbage-collected Processes. */
- private final ProcessReferenceQueue referenceQueue
- = new ProcessReferenceQueue();
- private ProcessManager() {
- // Spawn a thread to listen for signals from child processes.
- Thread processThread = new Thread(ProcessManager.class.getName()) {
- @Override
- public void run() {
- watchChildren();
- }
- };
- processThread.setDaemon(true);
- processThread.start();
- }
- /***
- * Kills the process with the given ID.
- *
- * @parm pid ID of process to kill
- */
- private static native void kill(int pid) throws IOException;
- /***
- * Cleans up after garbage collected processes. Requires the lock on the
- * map.
- */
- void cleanUp() {
- ProcessReference reference;
- while ((reference = referenceQueue.poll()) != null) {
- synchronized (processReferences) {
- processReferences.remove(reference.processId);
- }
- }
- }
- /***
- * Listens for signals from processes and calls back to
- * {@link #onExit(int,int)}.
- */
- native void watchChildren();
- /***
- * Called by {@link #watchChildren()} when a child process exits.
- *
- * @param pid ID of process that exited
- * @param exitValue value the process returned upon exit
- */
- void onExit(int pid, int exitValue) {
- ProcessReference processReference = null;
- synchronized (processReferences) {
- cleanUp();
- if (pid >= 0) {
- processReference = processReferences.remove(pid);
- } else if (exitValue == WAIT_STATUS_NO_CHILDREN) {
- if (processReferences.isEmpty()) {
- /**
- * There are no eligible children; wait for one to be
- * added. The wait() will return due to the
- * notifyAll() call below.
- */
- try {
- processReferences.wait();
- } catch (InterruptedException ex) {
- // This should never happen.
- throw new AssertionError("unexpected interrupt");
- }
- } else {
- /**
- * A new child was spawned just before we entered
- * the synchronized block. We can just fall through
- * without doing anything special and land back in
- * the native wait().
- */
- }
- } else {
- // Something weird is happening; abort!
- throw new AssertionError("unexpected wait() behavior");
- }
- }
- if (processReference != null) {
- ProcessImpl process = processReference.get();
- if (process != null) {
- process.setExitValue(exitValue);
- }
- }
- }
- /***
- * Executes a native process. Fills in in, out, and err and returns the
- * new process ID upon success.
- */
- static native int exec(String[] command, String[] environment,
- String workingDirectory, FileDescriptor in, FileDescriptor out,
- FileDescriptor err, boolean redirectErrorStream) throws IOException;
- /***
- * Executes a process and returns an object representing it.
- */
- Process exec(String[] taintedCommand, String[] taintedEnvironment, File workingDirectory,
- boolean redirectErrorStream) throws IOException {
- // Make sure we throw the same exceptions as the RI.
- if (taintedCommand == null) {
- throw new NullPointerException();
- }
- if (taintedCommand.length == 0) {
- throw new IndexOutOfBoundsException();
- }
- // Handle security and safety by copying mutable inputs and checking them.
- String[] command = taintedCommand.clone();
- String[] environment = taintedEnvironment != null ? taintedEnvironment.clone() : null;
- SecurityManager securityManager = System.getSecurityManager();
- if (securityManager != null) {
- securityManager.checkExec(command[0]);
- }
- // Check we're not passing null Strings to the native exec.
- for (String arg : command) {
- if (arg == null) {
- throw new NullPointerException();
- }
- }
- // The environment is allowed to be null or empty, but no element may be null.
- if (environment != null) {
- for (String env : environment) {
- if (env == null) {
- throw new NullPointerException();
- }
- }
- }
- FileDescriptor in = new FileDescriptor();
- FileDescriptor out = new FileDescriptor();
- FileDescriptor err = new FileDescriptor();
- String workingPath = (workingDirectory == null)
- ? null
- : workingDirectory.getPath();
- // Ensure onExit() doesn't access the process map before we add our
- // entry.
- synchronized (processReferences) {
- int pid;
- try {
- pid = exec(command, environment, workingPath, in, out, err, redirectErrorStream);
- } catch (IOException e) {
- IOException wrapper = new IOException("Error running exec()."
- + " Command: " + Arrays.toString(command)
- + " Working Directory: " + workingDirectory
- + " Environment: " + Arrays.toString(environment));
- wrapper.initCause(e);
- throw wrapper;
- }
- ProcessImpl process = new ProcessImpl(pid, in, out, err);
- ProcessReference processReference
- = new ProcessReference(process, referenceQueue);
- processReferences.put(pid, processReference);
- /**
- * This will wake up the child monitor thread in case there
- * weren't previously any children to wait on.
- */
- processReferences.notifyAll();
- return process;
- }
- }
- static class ProcessImpl extends Process {
- /*** Process ID. */
- final int id;
- final InputStream errorStream;
- /*** Reads output from process. */
- final InputStream inputStream;
- /*** Sends output to process. */
- final OutputStream outputStream;
- /*** The process's exit value. */
- Integer exitValue = null;
- final Object exitValueMutex = new Object();
- ProcessImpl(int id, FileDescriptor in, FileDescriptor out,
- FileDescriptor err) {
- this.id = id;
- this.errorStream = new ProcessInputStream(err);
- this.inputStream = new ProcessInputStream(in);
- this.outputStream = new ProcessOutputStream(out);
- }
- public void destroy() {
- try {
- kill(this.id);
- } catch (IOException e) {
- Logger.getLogger(Runtime.class.getName()).log(Level.FINE,
- "Failed to destroy process " + id + ".", e);
- }
- }
- public int exitValue() {
- synchronized (exitValueMutex) {
- if (exitValue == null) {
- throw new IllegalThreadStateException(
- "Process has not yet terminated.");
- }
- return exitValue;
- }
- }
- public InputStream getErrorStream() {
- return this.errorStream;
- }
- public InputStream getInputStream() {
- return this.inputStream;
- }
- public OutputStream getOutputStream() {
- return this.outputStream;
- }
- public int waitFor() throws InterruptedException {
- synchronized (exitValueMutex) {
- while (exitValue == null) {
- exitValueMutex.wait();
- }
- return exitValue;
- }
- }
- void setExitValue(int exitValue) {
- synchronized (exitValueMutex) {
- this.exitValue = exitValue;
- exitValueMutex.notifyAll();
- }
- }
- @Override
- public String toString() {
- return "Process[id=" + id + "]";
- }
- }
- static class ProcessReference extends WeakReference
{ - final int processId;
- public ProcessReference(ProcessImpl referent,
- ProcessReferenceQueue referenceQueue) {
- super(referent, referenceQueue);
- this.processId = referent.id;
- }
- }
- static class ProcessReferenceQueue extends ReferenceQueue
{ - @Override
- public ProcessReference poll() {
- // Why couldn't they get the generics right on ReferenceQueue? :(
- Object reference = super.poll();
- return (ProcessReference) reference;
- }
- }
- static final ProcessManager instance = new ProcessManager();
- /*** Gets the process manager. */
- static ProcessManager getInstance() {
- return instance;
- }
- /*** Automatically closes fd when collected. */
- private static class ProcessInputStream extends FileInputStream {
- private FileDescriptor fd;
- private ProcessInputStream(FileDescriptor fd) {
- super(fd);
- this.fd = fd;
- }
- @Override
- public void close() throws IOException {
- try {
- super.close();
- } finally {
- synchronized (this) {
- if (fd != null && fd.valid()) {
- try {
- ProcessManager.close(fd);
- } finally {
- fd = null;
- }
- }
- }
- }
- }
- }
- /*** Automatically closes fd when collected. */
- private static class ProcessOutputStream extends FileOutputStream {
- private FileDescriptor fd;
- private ProcessOutputStream(FileDescriptor fd) {
- super(fd);
- this.fd = fd;
- }
- @Override
- public void close() throws IOException {
- try {
- super.close();
- } finally {
- synchronized (this) {
- if (fd != null && fd.valid()) {
- try {
- ProcessManager.close(fd);
- } finally {
- fd = null;
- }
- }
- }
- }
- }
- }
- /*** Closes the given file descriptor. */
- private static native void close(FileDescriptor fd) throws IOException;
- }
#p#
在其中有一個“ native void watchChildren();”方法,此方法為線程主方法,具體實現(xiàn)可以看看JNI,在其中回調了方法:“ void onExit(int pid, int exitValue);” 在方法中:
- void onExit(int pid, int exitValue) {
- ProcessReference processRefe
文章題目:Process 創(chuàng)建+控制+分析 經(jīng)驗淺談
本文URL:http://www.fisionsoft.com.cn/article/ccchepd.html


咨詢
建站咨詢
