Process 创建+控制+分析 经验浅谈

无论是Android亦或者Java中或多或少需要调用底层的一些命令,执行一些参数;

在石拐等地区,都构建了全面的区域性战略布局,加强发展的系统性、市场前瞻性、产品创新能力,以专注、极致的服务理念,为客户提供做网站、成都做网站 网站设计制作定制网站,公司网站建设,企业网站建设,品牌网站设计,成都全网营销推广,外贸营销网站建设,石拐网站建设费用合理。

此时我们需要用到Java的process来创建一个子进程,之所以是子进程是因为此进程依赖于发起创建请求的进程,如果发起者被Kill那个子进程也将Kill。

对于Process相信使用过的朋友一定不会陌生,它具有如下特点:

1.创建简单

2.控制难

3.容易导致无法创建子进程

4.如果是多线程那么很有可能造成内存溢出

以上现象如果你只是偶尔使用一次,创建一个进程或许你什么都没有感觉到,但是如果你使用了多线程,进行了大量的创建,以上问题你都会遇到。

相关:http://blog.csdn.net/qiujuer/article/details/38142273,http://blog.csdn.net/qiujuer/article/details/38086071

这两个星期一直在研究上面的问题,我要做的软件是在Android中进行TraceRoute,由于手机不可能完全Root所以不能采用JNI来发送ICMP请求的方式,最终只能使用创建进程方式进行;具体实现思路是:使用PING命令来PING百度等地址,在PING命令中加入TTL,得到每一次的IP地址,当IP地址与目标IP地址符合时退出,并且还需要单独PING一次每一跳的延迟和丢包。

单线程:PING 百度 TTL=1 =》 得到IP,PING IP 得到延迟丢包,改变TTL,进行下一次PING,直到所得到的IP与目标(百度)一样时停止。按照上面的思路一次需要创建两个子进程,一般到百度时TTL大约为12跳左右,所以就是2*12=24个子进程;如果是在单线程下简单明了,但是速度慢,整个过程大约需要1分钟左右。

多线程:同时发起3个线程进行3跳测试TTL=(1,2,3),测试完成后测试下一批数据TTL=(4,5,6),如果也是12跳的话,那么也是24个子进程,但是整体耗时将会为1/3.可见此时效率较高。

但是多线程需要考虑的是线程的同步问题,以及得到数据后的写入问题,这些赞不谈,只谈进程问题。经过我的测试假如现在测试100个网站的TraceRoute数据,在上层控制一次测试4个网站,底层实现并发3个线程,此时在一定时间内将会同时存在3*4个进程。按照平均每个网站12跳来算:12*2*100=240个子进程,需要的子线程为12*100=120个。

这个时候问题来了,假如现在程序子进程不正常了,遇到了一个一定的问题导致进程无法执行完成,此时你的现象是:一个子进程卡住,随后创建的所有子进程都卡住。假如最上层线程做了任务时间限制,那么到时间后将会尝试销毁,但是你会发现无法销毁,所持有的线程也不会销毁。但是上层以为销毁掉了,然后继续进行下一批的数据测试,此时你的线程数量会逐渐增加,如果100任务下来你的线程或许会达到3*4*100=1200如果有前期没有这样的情况那个就是一半:600个线程左右,如果后期还有任务将会继续增加但是却永远不会销毁,但是我们知道JVM的内存是有限的,所以此时将会出现内存溢出。
以上就是我遇到的问题,我***改为了等待线程完全返回后再进行下一批数据测试,此时内存溢出是解决了,但是任务却一直卡住在哪里了,永远也不走。我就在想要解决这一的问题需要解决根本上的问题才行,经过研究我发现在程序创建了子进程后JVM将会创建一个子进程管理线程:“ProcessManager”:

正常情况下该线程状态为Native,但是如果创建大量子进程后有可能会出现此线程为Monitor状态,过一段时间后所有创建子进程的线程状态也将会变为Monitor状态,然后将一直死锁,后面创建线程也是继续死锁,无法继续。

通过查看ProcessManager源码发现,其中启动了一个线程用于监听子进程状态,同时管理子进程,比如输出消息以及关闭子进程等操作,具体如下

 
 
 
 
  1. /** 
  2.  * Copyright (C) 2007 The Android Open Source Project 
  3.  * 
  4.  * Licensed under the Apache License, Version 2.0 (the "License"); 
  5.  * you may not use this file except in compliance with the License. 
  6.  * You may obtain a copy of the License at 
  7.  * 
  8.  *      http://www.apache.org/licenses/LICENSE-2.0 
  9.  * 
  10.  * Unless required by applicable law or agreed to in writing, software 
  11.  * distributed under the License is distributed on an "AS IS" BASIS, 
  12.  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
  13.  * See the License for the specific language governing permissions and 
  14.  * limitations under the License. 
  15.  */ 
  16.   
  17. package java.lang; 
  18.   
  19. import java.io.File; 
  20. import java.io.FileDescriptor; 
  21. import java.io.FileInputStream; 
  22. import java.io.FileOutputStream; 
  23. import java.io.IOException; 
  24. import java.io.InputStream; 
  25. import java.io.OutputStream; 
  26. import java.lang.ref.ReferenceQueue; 
  27. import java.lang.ref.WeakReference; 
  28. import java.util.HashMap; 
  29. import java.util.Map; 
  30. import java.util.Arrays; 
  31. import java.util.logging.Logger; 
  32. import java.util.logging.Level; 
  33.   
  34. /*** 
  35.  * Manages child processes. 
  36.  * 
  37.  * 

    Harmony's native implementation (for comparison purposes): 

  38.  * http://tinyurl.com/3ytwuq 
  39.  */ 
  40. final class ProcessManager { 
  41.   
  42.     /*** 
  43.      * constant communicated from native code indicating that a 
  44.      * child died, but it was unable to determine the status 
  45.      */ 
  46.     private static final int WAIT_STATUS_UNKNOWN = -1; 
  47.   
  48.     /*** 
  49.      * constant communicated from native code indicating that there 
  50.      * are currently no children to wait for 
  51.      */ 
  52.     private static final int WAIT_STATUS_NO_CHILDREN = -2; 
  53.   
  54.     /*** 
  55.      * constant communicated from native code indicating that a wait() 
  56.      * call returned -1 and set an undocumented (and hence unexpected) errno 
  57.      */ 
  58.     private static final int WAIT_STATUS_STRANGE_ERRNO = -3; 
  59.   
  60.     /*** 
  61.      * Initializes native static state. 
  62.      */ 
  63.     static native void staticInitialize(); 
  64.     static { 
  65.         staticInitialize(); 
  66.     } 
  67.   
  68.     /*** 
  69.      * Map from pid to Process. We keep weak references to the Process objects 
  70.      * and clean up the entries when no more external references are left. The 
  71.      * process objects themselves don't require much memory, but file 
  72.      * descriptors (associated with stdin/out/err in this case) can be 
  73.      * a scarce resource. 
  74.      */ 
  75.     private final Map processReferences 
  76.             = new HashMap(); 
  77.   
  78.     /*** Keeps track of garbage-collected Processes. */ 
  79.     private final ProcessReferenceQueue referenceQueue 
  80.             = new ProcessReferenceQueue(); 
  81.   
  82.     private ProcessManager() { 
  83.         // Spawn a thread to listen for signals from child processes. 
  84.         Thread processThread = new Thread(ProcessManager.class.getName()) { 
  85.             @Override 
  86.             public void run() { 
  87.                 watchChildren(); 
  88.             } 
  89.         }; 
  90.         processThread.setDaemon(true); 
  91.         processThread.start(); 
  92.     } 
  93.   
  94.     /*** 
  95.      * Kills the process with the given ID. 
  96.      * 
  97.      * @parm pid ID of process to kill 
  98.      */ 
  99.     private static native void kill(int pid) throws IOException; 
  100.   
  101.     /*** 
  102.      * Cleans up after garbage collected processes. Requires the lock on the 
  103.      * map. 
  104.      */ 
  105.     void cleanUp() { 
  106.         ProcessReference reference; 
  107.         while ((reference = referenceQueue.poll()) != null) { 
  108.             synchronized (processReferences) { 
  109.                 processReferences.remove(reference.processId); 
  110.             } 
  111.         } 
  112.     } 
  113.   
  114.     /*** 
  115.      * Listens for signals from processes and calls back to 
  116.      * {@link #onExit(int,int)}. 
  117.      */ 
  118.     native void watchChildren(); 
  119.   
  120.     /*** 
  121.      * Called by {@link #watchChildren()} when a child process exits. 
  122.      * 
  123.      * @param pid ID of process that exited 
  124.      * @param exitValue value the process returned upon exit 
  125.      */ 
  126.     void onExit(int pid, int exitValue) { 
  127.         ProcessReference processReference = null; 
  128.   
  129.         synchronized (processReferences) { 
  130.             cleanUp(); 
  131.             if (pid >= 0) { 
  132.                 processReference = processReferences.remove(pid); 
  133.             } else if (exitValue == WAIT_STATUS_NO_CHILDREN) { 
  134.                 if (processReferences.isEmpty()) { 
  135.                     /** 
  136.                      * There are no eligible children; wait for one to be 
  137.                      * added. The wait() will return due to the 
  138.                      * notifyAll() call below. 
  139.                      */ 
  140.                     try { 
  141.                         processReferences.wait(); 
  142.                     } catch (InterruptedException ex) { 
  143.                         // This should never happen. 
  144.                         throw new AssertionError("unexpected interrupt"); 
  145.                     } 
  146.                 } else { 
  147.                     /** 
  148.                      * A new child was spawned just before we entered 
  149.                      * the synchronized block. We can just fall through 
  150.                      * without doing anything special and land back in 
  151.                      * the native wait(). 
  152.                      */ 
  153.                 } 
  154.             } else { 
  155.                 // Something weird is happening; abort! 
  156.                 throw new AssertionError("unexpected wait() behavior"); 
  157.             } 
  158.         } 
  159.   
  160.         if (processReference != null) { 
  161.             ProcessImpl process = processReference.get(); 
  162.             if (process != null) { 
  163.                 process.setExitValue(exitValue); 
  164.             } 
  165.         } 
  166.     } 
  167.   
  168.     /*** 
  169.      * Executes a native process. Fills in in, out, and err and returns the 
  170.      * new process ID upon success. 
  171.      */ 
  172.     static native int exec(String[] command, String[] environment, 
  173.             String workingDirectory, FileDescriptor in, FileDescriptor out, 
  174.             FileDescriptor err, boolean redirectErrorStream) throws IOException; 
  175.   
  176.     /*** 
  177.      * Executes a process and returns an object representing it. 
  178.      */ 
  179.     Process exec(String[] taintedCommand, String[] taintedEnvironment, File workingDirectory, 
  180.             boolean redirectErrorStream) throws IOException { 
  181.         // Make sure we throw the same exceptions as the RI. 
  182.         if (taintedCommand == null) { 
  183.             throw new NullPointerException(); 
  184.         } 
  185.         if (taintedCommand.length == 0) { 
  186.             throw new IndexOutOfBoundsException(); 
  187.         } 
  188.   
  189.         // Handle security and safety by copying mutable inputs and checking them. 
  190.         String[] command = taintedCommand.clone(); 
  191.         String[] environment = taintedEnvironment != null ? taintedEnvironment.clone() : null; 
  192.         SecurityManager securityManager = System.getSecurityManager(); 
  193.         if (securityManager != null) { 
  194.             securityManager.checkExec(command[0]); 
  195.         } 
  196.         // Check we're not passing null Strings to the native exec. 
  197.         for (String arg : command) { 
  198.             if (arg == null) { 
  199.                 throw new NullPointerException(); 
  200.             } 
  201.         } 
  202.         // The environment is allowed to be null or empty, but no element may be null. 
  203.         if (environment != null) { 
  204.             for (String env : environment) { 
  205.                 if (env == null) { 
  206.                     throw new NullPointerException(); 
  207.                 } 
  208.             } 
  209.         } 
  210.   
  211.         FileDescriptor in = new FileDescriptor(); 
  212.         FileDescriptor out = new FileDescriptor(); 
  213.         FileDescriptor err = new FileDescriptor(); 
  214.   
  215.         String workingPath = (workingDirectory == null) 
  216.                 ? null 
  217.                 : workingDirectory.getPath(); 
  218.   
  219.         // Ensure onExit() doesn't access the process map before we add our 
  220.         // entry. 
  221.         synchronized (processReferences) { 
  222.             int pid; 
  223.             try { 
  224.                 pid = exec(command, environment, workingPath, in, out, err, redirectErrorStream); 
  225.             } catch (IOException e) { 
  226.                 IOException wrapper = new IOException("Error running exec()." 
  227.                         + " Command: " + Arrays.toString(command) 
  228.                         + " Working Directory: " + workingDirectory 
  229.                         + " Environment: " + Arrays.toString(environment)); 
  230.                 wrapper.initCause(e); 
  231.                 throw wrapper; 
  232.             } 
  233.             ProcessImpl process = new ProcessImpl(pid, in, out, err); 
  234.             ProcessReference processReference 
  235.                     = new ProcessReference(process, referenceQueue); 
  236.             processReferences.put(pid, processReference); 
  237.   
  238.             /** 
  239.              * This will wake up the child monitor thread in case there 
  240.              * weren't previously any children to wait on. 
  241.              */ 
  242.             processReferences.notifyAll(); 
  243.   
  244.             return process; 
  245.         } 
  246.     } 
  247.   
  248.     static class ProcessImpl extends Process { 
  249.   
  250.         /*** Process ID. */ 
  251.         final int id; 
  252.   
  253.         final InputStream errorStream; 
  254.   
  255.         /*** Reads output from process. */ 
  256.         final InputStream inputStream; 
  257.   
  258.         /*** Sends output to process. */ 
  259.         final OutputStream outputStream; 
  260.   
  261.         /*** The process's exit value. */ 
  262.         Integer exitValue = null; 
  263.         final Object exitValueMutex = new Object(); 
  264.   
  265.         ProcessImpl(int id, FileDescriptor in, FileDescriptor out, 
  266.                 FileDescriptor err) { 
  267.             this.id = id; 
  268.   
  269.             this.errorStream = new ProcessInputStream(err); 
  270.             this.inputStream = new ProcessInputStream(in); 
  271.             this.outputStream = new ProcessOutputStream(out); 
  272.         } 
  273.   
  274.         public void destroy() { 
  275.             try { 
  276.                 kill(this.id); 
  277.             } catch (IOException e) { 
  278.                 Logger.getLogger(Runtime.class.getName()).log(Level.FINE, 
  279.                         "Failed to destroy process " + id + ".", e); 
  280.             } 
  281.         } 
  282.   
  283.         public int exitValue() { 
  284.             synchronized (exitValueMutex) { 
  285.                 if (exitValue == null) { 
  286.                     throw new IllegalThreadStateException( 
  287.                             "Process has not yet terminated."); 
  288.                 } 
  289.   
  290.                 return exitValue; 
  291.             } 
  292.         } 
  293.   
  294.         public InputStream getErrorStream() { 
  295.             return this.errorStream; 
  296.         } 
  297.   
  298.         public InputStream getInputStream() { 
  299.             return this.inputStream; 
  300.         } 
  301.   
  302.         public OutputStream getOutputStream() { 
  303.             return this.outputStream; 
  304.         } 
  305.   
  306.         public int waitFor() throws InterruptedException { 
  307.             synchronized (exitValueMutex) { 
  308.                 while (exitValue == null) { 
  309.                     exitValueMutex.wait(); 
  310.                 } 
  311.                 return exitValue; 
  312.             } 
  313.         } 
  314.   
  315.         void setExitValue(int exitValue) { 
  316.             synchronized (exitValueMutex) { 
  317.                 this.exitValue = exitValue; 
  318.                 exitValueMutex.notifyAll(); 
  319.             } 
  320.         } 
  321.   
  322.         @Override 
  323.         public String toString() { 
  324.             return "Process[id=" + id + "]";  
  325.         } 
  326.     } 
  327.   
  328.     static class ProcessReference extends WeakReference { 
  329.   
  330.         final int processId; 
  331.   
  332.         public ProcessReference(ProcessImpl referent, 
  333.                 ProcessReferenceQueue referenceQueue) { 
  334.             super(referent, referenceQueue); 
  335.             this.processId = referent.id; 
  336.         } 
  337.     } 
  338.   
  339.     static class ProcessReferenceQueue extends ReferenceQueue { 
  340.   
  341.         @Override 
  342.         public ProcessReference poll() { 
  343.             // Why couldn't they get the generics right on ReferenceQueue? :( 
  344.             Object reference = super.poll(); 
  345.             return (ProcessReference) reference; 
  346.         } 
  347.     } 
  348.   
  349.     static final ProcessManager instance = new ProcessManager(); 
  350.   
  351.     /*** Gets the process manager. */ 
  352.     static ProcessManager getInstance() { 
  353.         return instance; 
  354.     } 
  355.   
  356.     /*** Automatically closes fd when collected. */ 
  357.     private static class ProcessInputStream extends FileInputStream { 
  358.   
  359.         private FileDescriptor fd; 
  360.   
  361.         private ProcessInputStream(FileDescriptor fd) { 
  362.             super(fd); 
  363.             this.fd = fd; 
  364.         } 
  365.   
  366.         @Override 
  367.         public void close() throws IOException { 
  368.             try { 
  369.                 super.close(); 
  370.             } finally { 
  371.                 synchronized (this) { 
  372.                     if (fd != null && fd.valid()) { 
  373.                         try { 
  374.                             ProcessManager.close(fd); 
  375.                         } finally { 
  376.                             fd = null; 
  377.                         } 
  378.                     } 
  379.                 } 
  380.             } 
  381.         } 
  382.     } 
  383.   
  384.     /*** Automatically closes fd when collected. */ 
  385.     private static class ProcessOutputStream extends FileOutputStream { 
  386.   
  387.         private FileDescriptor fd; 
  388.   
  389.         private ProcessOutputStream(FileDescriptor fd) { 
  390.             super(fd); 
  391.             this.fd = fd; 
  392.         } 
  393.   
  394.         @Override 
  395.         public void close() throws IOException { 
  396.             try { 
  397.                 super.close(); 
  398.             } finally { 
  399.                 synchronized (this) { 
  400.                     if (fd != null && fd.valid()) { 
  401.                         try { 
  402.                             ProcessManager.close(fd); 
  403.                         } finally { 
  404.                             fd = null; 
  405.                         } 
  406.                     } 
  407.                 } 
  408.             } 
  409.         } 
  410.     } 
  411.   
  412.     /*** Closes the given file descriptor. */ 
  413.     private static native void close(FileDescriptor fd) throws IOException; 

#p#

在其中有一个“ native void watchChildren();”方法,此方法为线程主方法,具体实现可以看看JNI,在其中回调了方法:“ void onExit(int pid, int exitValue);” 在方法中:

 
 
 
 
  1. void onExit(int pid, int exitValue) { 
  2.         ProcessReference processRefe

    网页标题:Process 创建+控制+分析 经验浅谈
    文章网址:http://www.stwzsj.com/qtweb/news29/11829.html

    网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

    广告

    声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联