Android 多進程開發

前言


? ? ? ?正常情況下,一個apk啟動后只會運行在一個進程中,其進程名為AndroidManifest.xml文件中指定的應用包名,所有的基本組件都會在這個進程中運行。但是如果需要將某些組件(如Service、Activity等)運行在單獨的進程中,就需要用到android:process屬性了。我們可以為android的基礎組件指定process屬性來指定它們運行在指定進程中。android使用多進程重構項目架構,可以分擔主進程壓力以免因資源消耗過大被crash掉,另外多進程相互監聽喚醒,可以使應用程序長期駐守后臺接受即時消息和通知,防止應用被系統回收。下面就總結一下多進程開發的經驗及優化。


一、多進程概念


? ? ? ?一般情況下,一個應用程序就是一個進程,這個進程名稱就是應用程序包名。我們知道進程是系統分配資源和調度的基本單位,所以每個進程都有自己獨立的資源和內存空間,別的進程是不能任意訪問其他進程的內存和資源的。


二、多進程機制


? ? ? ?四大組件在AndroidManifest文件中注冊的時候,有個屬性android:process這里可以指定組件的所處的進程。

? ? ? ?對process屬性的設置有兩種形式:

? ? ? ?第一種形式:android:process=":remote",以冒號開頭,冒號后面的字符串原則上是可以隨意指定的。如果我們的包名為“com.example.processtest”,則實際的進程名為“com.example.processtest:remote”。這種設置形式表示該進程為當前應用的私有進程,其他應用的組件不可以和它跑在同一個進程中。

? ? ? ?第二種形式:android:process="com.example.processtest.remote",以小寫字母開頭,表示運行在一個以這個名字命名的全局進程中,其他應用通過設置相同的ShareUID可以和它跑在同一個進程。

? ? ? ?下面通過一個例子來進行一下驗證。我們定義兩個類:ProcessTestActivity和ProcessTestService,然后在AndroidManifest.xml文件中增加這兩個類,并為我們的Service指定一個process屬性,代碼如下:

<?xml version="1.0" encoding="utf-8"?>  
<manifest xmlns:android="http://schemas.android.com/apk/res/android"  package="com.example.processtest"  android:versionCode="1"  android:versionName="1.0" >  <uses-sdk  android:minSdkVersion="8"  android:targetSdkVersion="19" />  <application  android:name="com.example.processtest.MyApplication"  android:icon="@drawable/ic_launcher"  android:label="@string/app_name">  <activity  android:name=".ProcessTestActivity"  android:label="@string/app_name" >  <intent-filter>  <action android:name="android.intent.action.MAIN" />  <category android:name="android.intent.category.LAUNCHER" />  </intent-filter>  </activity>  <service  android:name=".ProcessTestService"  android:process=":remote">  </service>  </application>  </manifest>

運行代碼,通過DDMS進行觀察


? ? ? ?我們可以看到兩個進程,名字分別是“com.example.processtest”和“com.example.processtest:remote”,進程ID分別為2722和2739。

? ? ? ?ProcessTestService運行在一個單獨的私有進程中,如果想讓ProcessTestService運行在一個全局進程中,那么只需修改android:process="com.example.processtest.remote"即可。Android為每一個應用程序分配了一個獨立的虛擬機,或者說為每個進程都分配了一個獨立的虛擬機,不同的虛擬機在內存分配上 有不同的地址空間,這就會導致在不同的虛擬機中訪問同一類的對象會產生多份副本。在一個進程中修改某個值只會影響當前進程,對其他進程不會造成任何影響。


三、多進程優點


一般來說,Android應用多進程有三個好處:

? ? ? ?1)我們知道Android系統對每個應用進程的內存占用是有限制的,而且占用內存越大的進程,通常被系統殺死的可能性越大。讓一個組件運行在單獨的進程中,可以減少主進程所占用的內存,降低被系統殺死的概率.

? ? ? ?2)如果子進程因為某種原因崩潰了,不會直接導致主程序的崩潰,可以降低我們程序的崩潰率。

? ? ? ?3)即使主進程退出了,我們的子進程仍然可以繼續工作,假設子進程是推送服務,在主進程退出的情況下,仍然能夠保證用戶可以收到推送消息。


四、多進程缺點


? ? ? ?我們已經開啟了應用內多進程,那么,開啟多進程是不是只是我們看到的這么簡單呢?其實這里面會有一些陷阱,稍微不注意就會陷入其中。我們首先要明確的一點是進程間的內存空間時不可見的。

從而,開啟多進程后,我們需要面臨這樣幾個問題:

? ? ? ?1)Application的多次重建。運行在同一個進程中的組件是屬于同一個虛擬機和同一個Application的,運行在不同進程中的組件是屬于兩個不同的虛擬機和Application的。

? ? ? ?2)靜態成員和單例模式完全失效。

? ? ? ?3)文件共享問題。比如SharedPreferences 的可靠性下降。

? ? ? ?4)斷點調試問題。


1、Application的多次重建

我們先通過一個簡單的例子來看一下第一種情況。

? ? ? ?Manifest文件如上面提到的,定義了兩個類:ProcessTestActivity和ProcessTestService,我們只是在Activity的onCreate方法中直接啟動了該Service,同時,我們自定義了自己的Application類。代碼如下:

public class MyApplication extends Application {  public static final String TAG = "viclee";  @Override  public void onCreate() {  super.onCreate();  int pid = android.os.Process.myPid();  Log.d(TAG, "MyApplication onCreate");  Log.d(TAG, "MyApplication pid is " + pid);  }  
}  
public class ProcessTestActivity extends Activity {  public final static String TAG = "viclee";  @Override  protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_process_test);  Log.i(TAG, "ProcessTestActivity onCreate");  this.startService(new Intent(this, ProcessTestService.class));  }  
}  
public class ProcessTestService extends Service {  public static final String TAG = "viclee";  @Override  public void onCreate() {  Log.i(TAG, "ProcessTestService onCreate");  }  @Override  public IBinder onBind(Intent arg0) {  return null;  }  }  
執行上面這段代碼,查看打印信息:


? ? ? ?我們發現MyApplication的onCreate方法調用了兩次,分別是在啟動ProcessTestActivity和ProcessTestService的時候,而且我們發現打印出來的pid也不相同。由于通常會在Application的onCreate方法中做一些全局的初始化操作,它被初始化多次是完全沒有必要的。出現這種情況,是由于即使是通過指定process屬性啟動新進程的情況下,系統也會新建一個獨立的虛擬機,自然需要重新初始化一遍Application。那么怎么來解決這個問題呢?

? ? ? ?我們可以通過在自定義的Application中通過進程名來區分當前是哪個進程,然后單獨進行相應的邏輯處理。

public class MyApplication extends Application {  public static final String TAG = "viclee";  @Override  public void onCreate() {  super.onCreate();  int pid = android.os.Process.myPid();  Log.d(TAG, "MyApplication onCreate");  Log.d(TAG, "MyApplication pid is " + pid);  ActivityManager am = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);  List<ActivityManager.RunningAppProcessInfo> runningApps = am.getRunningAppProcesses();  if (runningApps != null && !runningApps.isEmpty()) {  for (ActivityManager.RunningAppProcessInfo procInfo : runningApps) {  if (procInfo.pid == pid) {  if (procInfo.processName.equals("com.example.processtest")) {  Log.d(TAG, "process name is " + procInfo.processName);  } else if (procInfo.processName.equals("com.example.processtest:remote")) {  Log.d(TAG, "process name is " + procInfo.processName);  }  }  }  }  }  
} 

運行之后,查看Log信息:


? ? ? ?圖中可以看出,不同的進程執行了不同的代碼邏輯,可以通過這種方式來區分不同的進程需要完成的初始化工作。


2、靜態變量和單例模式完全失效

? ? ? ?下面我們來看第二個問題,將之前定義的Activity和Service的代碼進行簡單的修改,代碼如下:

public class ProcessTestActivity extends Activity {  public final static String TAG = "viclee";  public static boolean processFlag = false;  @Override  protected void onCreate(Bundle savedInstanceState) {  super.onCreate(savedInstanceState);  setContentView(R.layout.activity_process_test);  processFlag = true;  Log.i(TAG, "ProcessTestActivity onCreate");  this.startService(new Intent(this, ProcessTestService.class));  }  
}  
public class ProcessTestService extends Service {  public static final String TAG = "viclee";  @Override  public void onCreate() {  Log.i(TAG, "ProcessTestService onCreate");  Log.i(TAG, "ProcessTestActivity.processFlag is " + ProcessTestActivity.processFlag);  }  @Override  public IBinder onBind(Intent arg0) {  return null;  }  }
重新執行代碼,打印Log:


? ? ? ? 從上面的代碼和執行結果看,我們在Activity中定義了一個標志processFlag并在onCreate中修改了它的值為true,然后啟動Service,但是在Service中讀到這個值卻為false。按照正常的邏輯,靜態變量是可以在應用的所有地方共享的,但是設置了process屬性后,產生了兩個隔離的內存空間,一個內存空間里值的修改并不會影響到另外一個內存空間。

? ? ? ?針對靜態變量失效的問題,我們可以使用Intent或者aidl等進程通訊方式傳遞內容。


3、文件共享問題
? ? ? ?第三個問題是文件共享問題。多進程情況下會出現兩個進程在同一時刻訪問同一個數據庫文件的情況。這就可能造成資源的競爭訪問,導致諸如數據庫損壞、數據丟失等。在多線程的情況下我們有鎖機制控制資源的共享,但是在多進程中比較難,雖然有文件鎖、排隊等機制,但是在Android里很難實現。解決辦法就是多進程的時候不并發訪問同一個文件,比如子進程涉及到操作數據庫,就可以考慮調用主進程進行數據庫的操作。


4、斷點調試問題

? ? ? ?最后是斷點調試的問題。調試就是跟蹤程序運行過程中的堆棧信息,由于每個進程都有自己獨立的內存空間和各自的堆棧,無法實現在不同的進程間調試。不過可以通過下面的方式實現:調試時去掉AndroidManifest.xml中android:process標簽,這樣保證調試狀態下是在同一進程中,堆棧信息是連貫的。待調試完成后,再將標簽復原。


五、多進程使用場景


? ? ? ?類似音樂類、跑步健身類、手機管家類等長時間需要在后臺運行的應用。這些應用的特點就是,當用戶切到別的應用,或者關掉手機屏幕的時候,應用本身的核心模塊還在正常運行,提供服務。如果因為手機內存過低,或者是進程重要性降低,導致應用被殺掉,后臺服務停止,對于這些應用來說,就是滅頂之災。合理利用多進程,將核心后臺服務模塊和其他UI模塊進行分離,保證應用能更穩定的提供服務,從而提升用戶體驗。


舉個例子:

現在要做一款音樂播放器,現在有以下幾種方案:
A. 在Activity中直接播放音樂。
B. 啟動后臺Service,播放音樂。
C. 啟動前臺Service,播放音樂。
D. 在新的進程中,啟動后臺Service,播放音樂。
E. 在新的進程中,啟動前臺Service,播放音樂。


A. 在Activity中直接播放音樂。
? ? ? ?在A中,我們的播放器是直接在activity中啟動的。首先這么做肯定是不對的,我們需要在后臺播放音樂,所以當activity退出后就播不了了,之所以給出這個例子是為了控制變量作對比。
? ? ? ?然后我們來看下A的使用場景。
? ? ? ?音樂播放器無非是打開app,選歌,播放,退到桌面,切其他應用。我們選取了三個場景,打開、按home切換其他應用、按back退回桌面。讓我們看一下A的相對應的oom_adj、oom_score、oom_score_adj的值。(下面三張圖依次對應為【打開狀態】、【按了Home鍵被切換狀態】、【按了Back鍵被退出狀態】)

上圖為打開狀態下oom_adj、oom_score、oom_score_adj的值

上圖為按了Home鍵狀態下oom_adj、oom_score、oom_score_adj的值

上圖為按了Back鍵狀態下oom_adj、oom_score、oom_score_adj的值

? ? ? ?當我們應用在前臺的時候,無論adj還是score還是score_adj,他們的值都非常的小,基本不會被LMK所殺掉,但是當我們按了Home之后,進程的adj就會急劇增大,變為7,相應的score和score_adj也會增大。在上篇文章中我們得知,adj=7即為被切換的進程,兩個進程來回切換,上一個進程就會被設為7。當我們按Back鍵的時候,adj就會被設為9,也就是緩存進程,優先級比較低,有很大的幾率被殺掉。


B. 啟動后臺Service,播放音樂。
? ? ? ?B是直接啟動一個后臺service并且播放音樂,這個處理看起來比A好了很多,那么實際上,B的各個場景的優先級和A又有什么不同呢?讓我們來看下B的對應的打開、切換、退出相應的adj、score、score_adj的值。(下面三張圖依次對應為【打開狀態】、【按了Home鍵被切換狀態】、【按了Back鍵被退出狀態】)

上圖為打開狀態下oom_adj、oom_score、oom_score_adj的值

上圖為按了Home鍵狀態下oom_adj、oom_score、oom_score_adj的值

上圖為按了Back鍵狀態下oom_adj、oom_score、oom_score_adj的值

? ? ? ?B的情況其實是與A類似的,三種狀態的adj、score_adj的值都是一樣的,只有score有一點出入,其實分析源碼得知,LMK殺進程的時候,score的左右其實并不大,所以我們暫時忽略它。所以,與A相比,他們的adj和score_adj的值都相同,如果遇到內存不足的情況下,這兩個應用誰占得內存更大,誰就會被殺掉。不過鑒于A實在activity中播放音樂,所以B還是比A略好的方案。


C. 啟動前臺Service,播放音樂。
? ? ? ?C的話是啟動一個前臺Service來播放音樂。讓我們來看一下對應的值。(下面三張圖依次對應為【打開狀態】、【按了Home鍵被切換狀態】、【按了Back鍵被退出狀態】)

上圖為打開狀態下oom_adj、oom_score、oom_score_adj的值

上圖為按了Home鍵狀態下oom_adj、oom_score、oom_score_adj的值

上圖為按了Back鍵狀態下oom_adj、oom_score、oom_score_adj的值

? ? ? ?在前臺的時候,和AB是一樣的,adj都是0,當切到后臺,或者back結束時,C對應的adj就是2,也就是可感知進程。adj=2可以說是很高優先級了,非root手機,非系統應用已經沒有辦法將其殺掉了。adj<5的應用不會被殺掉。
? ? ? ?總的來說,C方案比B優秀,擁有前臺Service的C更不容易被系統或者其他應用所殺掉了,進程的優先級一下子提高到了2,相對于B來說更穩定,用戶體驗更好。不過有一點不足是必須啟動一個前臺service。不過現在大部分的音樂類軟件都會提供一個前臺service,也就不是什么缺點了。其實也是有灰色方法可以啟動一個不顯示通知的前臺service,這里就不過多介紹了。

那么還有可改進的余地嗎?
答案當然是肯定的。


D. 在新的進程中,啟動后臺Service,播放音樂。
? ? ? ?終于我們的主角,多進程登場了。
? ? ? ?D把應用進行了拆分,把用于播放音樂的service放到了新的進程內,讓我們看一下對應的值。(下面三張圖依次對應為【打開狀態】、【按了Home鍵被切換狀態】、【按了Back鍵被退出狀態】)

上圖為打開狀態下oom_adj、oom_score、oom_score_adj的值

上圖為按了Home鍵狀態下oom_adj、oom_score、oom_score_adj的值

上圖為按了Back鍵狀態下oom_adj、oom_score、oom_score_adj的值

? ? ? ?上面三張圖對應的是D應用主進程的ADJ相關值,我們可以看出來,跟A類似,adj都是0,7,9。由于少了service部分,內存使用變少,最后計算出的oom_score_adj也更低了,意味著主進程部分也更不容易被殺死。

下面我們看下拆分出的service的相關值

上圖為后臺Service的oom_adj、oom_score、oom_score_adj的值

? ? ? ?因為是service進程,所以不受打開,關閉,切換所影響,這里就放了一張圖。
? ? ? ?我們可以看到,service的adj值一直是5,也就是活躍的服務進程,相比于B來說,優先級高了不少。不過對于C來說,其實這個方案反倒不如C的adj=2的前臺進程更穩定。但是D可以自主釋放主進程,使D實際所占用的內存很小,從而不容易被殺掉。那么到底C和D誰是更優秀的設計?我個人認為,在ABCDE這5個設計中,D是最具智慧的設計,具體是為什么?先賣個關子,等我們說完了E,再作總結。


E. 在新的進程中,啟動前臺Service,播放音樂。

? ? ? ?E也是使用了多進程,并且在新進程中,使用了前臺service,先來看下對應的值。(下面三張圖依次對應為【打開狀態】、【按了Home鍵被切換狀態】、【按了Back鍵被退出狀態】)

上圖為打開狀態下oom_adj、oom_score、oom_score_adj的值

上圖為按了Home鍵狀態下oom_adj、oom_score、oom_score_adj的值

上圖為按了Back鍵狀態下oom_adj、oom_score、oom_score_adj的值

? ? ? ?這個不多解釋,和ABD基本差不多,都是0,7,9。我們看下拆分出來的進程的值。

上圖為后臺Service的oom_adj、oom_score、oom_score_adj的值
? ? ? ?我們可以看到,這個進程的值是2,像C方案,非常小,非常穩定,而且,我們還可以在系統進入后臺后,手動殺掉主進程,使整個應用的內存消耗降到最低,內存低,優先級又高,E獲得了今天的最穩定的方案獎。


小結
? ? ? ?ABCDE,5種方案都已經分析完了。顯然,E是最穩定的方案,不過,我剛才說過,我個人最傾向于D方案,并且認為D是最智慧的方案,這是為什么呢?
? ? ? ?其實我們可以做個比喻,把整個Android系統比喻成一個旅游景點,Low Memory Killer就是景點的門衛兼保安,然后我們每個進程的ADJ相當于手里的門票,有的人是VIP門票,有的人是普通門票。景點平常沒人的時候還好,誰拿票都能進,當人逐漸擁擠的時候,保安就開始根據票的等級,往外轟人。E方案就是一個拿著普通票的媽媽,帶著一個VIP的孩子去參觀,D方案就是一個拿著普通票的媽媽,帶著一個拿著中等票的孩子參觀。當內存不夠的時候,保安會先把兩個媽媽轟出去,孩子們在里面看,再不夠了,就會把D孩子給轟出去。這么看來,顯然E的效果更好一些,不過由于Android系統對于VIP票的發放沒有節制,大家都可以領VIP票,那也就是相當于沒有VIP票了。所以如果E方案是一種精明,那么D才是真正的智慧。將調度權還給系統,做好自己,維護好整個Android生態。

多模塊應用



? ? ? ?多進程還有一種非常有用的場景,就是多模塊應用。比如我做的應用大而全,里面肯定會有很多模塊,假如有地圖模塊、大圖瀏覽、自定義WebView等等(這些都是吃內存大戶),還會有一些諸如下載服務,監控服務等等,一個成熟的應用一定是多模塊化的。

? ? ? ?首先多進程開發能為應用解決了OOM問題,Android對內存的限制是針對于進程的,這個閾值可以是48M、24M、16M等,視機型而定,所以,當我們需要加載大圖之類的操作,可以在新的進程中去執行,避免主進程OOM。

? ? ? ?多進程不光解決OOM問題,還能更有效、合理的利用內存。我們可以在適當的時候生成新的進程,在不需要的時候及時殺掉,合理分配,提升用戶體驗。減少系統被殺掉的風險。

? ? ? ?多進程還能帶來一個好處就是,單一進程崩潰并不影響整體應用的使用。例如我在圖片瀏覽進程打開了一個過大的圖片,java heap 申請內存失敗,但是不影響我主進程的使用,而且,還能通過監控進程,將這個錯誤上報給系統,告知他在什么機型、環境下、產生了什么樣的Bug,提升用戶體驗。

? ? ? ?再一個好處就是,當我們的應用開發越來越大,模塊越來越多,團隊規模也越來越大,協作開發也是個很麻煩的事情。項目解耦,模塊化,是這階段的目標。通過模塊解耦,開辟新的進程,獨立的JVM,來達到數據解耦目的。模塊之間互不干預,團隊并行開發,責任分工也明確。至于模塊化開發與多進程的結合,后續會寫一篇專門的文章來研究這個問題。



本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/446967.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/446967.shtml
英文地址,請注明出處:http://en.pswp.cn/news/446967.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

clion中鏈接openssl庫

錯誤顯示 前提條件 apt-get install opensslapt-get install openssl-dev 解決辦法 在CMakeLists.txt文件中加入如下命令link_libraries(crypto) 參考鏈接 無法將openssl庫鏈接到CLion C 程序c - 無法將openssl庫鏈接到CLion C程序

Java中String、StringBuffer、StringBuilder三者的區別

一、簡介String、StringBuffer、StringBuilder三個類之間的區別主要是在兩個方面&#xff1a;運行速度和線程安全。二、區別1、運行速度&#xff0c;或者說是執行速度在這方面運行速度快慢為&#xff1a;StringBuilder > StringBuffer > String StringString為字符串常量…

Ubuntu環境下,使用clion編譯器,使用開源opensll的對稱AES算法對于文件進行加密,C++代碼

前提準備條件 需要安裝openssl需要安裝openssl-dev需要配置CMakeLists.txt文件集體內容可以參考我提供的相關參考鏈接 AES_file.h #include <openssl/aes.h> #include <iostream> #include <fstream> #include <cstring>#define RELEASE_ARRAY(P) if…

Java提高篇 —— Java關鍵字之static的四種用法

一、前言 在java的關鍵字中&#xff0c;static和final是兩個我們必須掌握的關鍵字。不同于其他關鍵字&#xff0c;他們都有多種用法&#xff0c;而且在一定環境下使用&#xff0c;可以提高程序的運行性能&#xff0c;優化程序的結構。下面我們先來了解一下static關鍵字及其用法…

C++ 使用move來刪除用戶指定的文件

代碼 #include <iostream>bool remove_file(std::string path){if (remove(path.c_str())0){std::cout << "success!" << std::endl;}else{std::cout << "False!" << std::endl;} } int main() {std::string path "/…

Java提高篇 —— Java關鍵字之final的幾種用法

一、前言 在java的關鍵字中&#xff0c;static和final是兩個我們必須掌握的關鍵字。不同于其他關鍵字&#xff0c;他們都有多種用法&#xff0c;而且在一定環境下使用&#xff0c;可以提高程序的運行性能&#xff0c;優化程序的結構。下面我們來了解一下final關鍵字及其用法。 …

使用C++的方式實現AES算法

aes_file.h #include <iostream> #include <fstream> #include <bitset> #include <string> using namespace std; typedef bitset<8> byte; typedef bitset<32> word;const int Nr 10; // AES-128需要 10 輪加密 const int Nk 4; /…

Java提高篇 —— Java三大特性之封裝

一、封裝 封裝從字面上來理解就是包裝的意思&#xff0c;專業點就是信息隱藏&#xff0c;是指利用抽象數據類型將數據和基于數據的操作封裝在一起&#xff0c;使其構成一個不可分割的獨立實體&#xff0c;數據被保護在抽象數據類型的內部&#xff0c;盡可能地隱藏內部的細節&am…

sqlite3的backup和restore函數的使用

參考代碼 第一段這個親測可以使用 #include <sqlite3.h> #include <iostream> /* ** Perform an online backup of database pDb to the database file named ** by zFilename. This function copies 5 database pages from pDb to ** zFilename, then unlocks pD…

Java提高篇 —— Java三大特性之繼承

一、前言 在《Think in java》中有這樣一句話&#xff1a;復用代碼是Java眾多引人注目的功能之一。但要想成為極具革命性的語言&#xff0c;僅僅能夠復制代碼并對加以改變是不夠的&#xff0c;它還必須能夠做更多的事情。在這句話中最引人注目的是“復用代碼”,盡可能的復用代碼…

Java提高篇 —— Java三大特性之多態

一、前言 面向對象編程有三大特性&#xff1a;封裝、繼承、多態。 封裝&#xff1a;隱藏了類的內部實現機制&#xff0c;可以在不影響使用的情況下改變類的內部結構&#xff0c;同時也保護了數據。對外界而已它的內部細節是隱藏的&#xff0c;暴露給外界的只是它的訪問方法。 繼…

光盤刻錄制作Ubuntu等操作系統的啟動盤

前提條件 軟媒刻錄 空白光盤&#xff08;至少4.7G&#xff09;電腦&#xff08;最好使用外置的光驅&#xff09;系統鏡像&#xff08;ISO格式&#xff09; 具體操作 打開軟媒魔方選擇光盤刻錄按照標紅的進行選擇選擇鏡像->選擇或者拖拽都可以選擇刻錄機->如果使用外部刻…

Java提高篇 —— 抽象類與接口

一、前言 接口和內部類為我們提供了一種將接口與實現分離的更加結構化的方法。 抽象類與接口是java語言中對抽象概念進行定義的兩種機制&#xff0c;正是由于他們的存在才賦予java強大的面向對象的能力。他們兩者之間對抽象概念的支持有很大的相似&#xff0c;甚至可以互換&…

C++ const相關內容學習

const 作用 修飾變量&#xff0c;說明變量不可以被修改修飾指針&#xff0c;分為指向常量的指針&#xff08;pointer to const&#xff09;和自身是常量的指針&#xff08;常量指針&#xff0c;const pointer&#xff09;修飾引用&#xff0c;指向常量的引用&#xff08;refe…

Java提高篇 —— Java淺拷貝和深拷貝

一、前言 我們知道在Java中存在這個接口Cloneable&#xff0c;實現該接口的類都會具備被拷貝的能力&#xff0c;同時拷貝是在內存中進行&#xff0c;在性能方面比我們直接通過new生成對象來的快&#xff0c;特別是在大對象的生成上&#xff0c;使得性能的提升非常明顯。然而我們…

openssl里面AES算法主要函數的參數的介紹

注意事項 使用API的時候&#xff0c;需要特別小心數據長度&#xff0c;一般沒有指定長度的參數&#xff0c;默認都是16&#xff08;AES_BLOCK_SIZE&#xff09;個字節。輸出數據的長度一般都是16字節的倍數&#xff0c;否則會出現數組越界訪問。以下API中&#xff0c;encrypt表…

Java提高篇 —— Java內部類詳解

一、簡介 內部類是一個非常有用的特性但又比較難理解使用的特性。 內部類我們從外面看是非常容易理解的&#xff0c;無非就是在一個類的內部在定義一個類。 public class OuterClass {private String name ;private int age;public String getName() {return name;}public voi…

Ubuntu修改界面的大小

命令 xrandr 就會顯示ubuntu支持的屏幕比例使用命令 xrandr --size 1680x1050 切換屏幕大小

Java提高篇 —— String緩沖池

一、String緩沖池 首先我們要明確&#xff0c;String并不是基本數據類型&#xff0c;而是一個對象&#xff0c;并且是不可變的對象。查看源碼就會發現String類為final型的&#xff08;當然也不可被繼承&#xff09;&#xff0c;而且通過查看JDK文檔會發現幾乎每一個修改String對…

C++最新使用開源openssl實現輸入是文件,輸出是文件的AES加解密的代碼

AES.h頭文件 #include <cstring> #include <fstream> #include <iostream> #include <openssl/aes.h>//AES文件加密函數 int aes_encrypt_file(const std::string &original_backup_file_path,const std::string &encrypted_file_path,const …