主頁 >  其他 > 第五章 虛擬機位元組碼執行引擎

第五章 虛擬機位元組碼執行引擎

2021-09-11 13:57:40 其他

  1. 概述  

  虛擬機是一個相對于物理機的概念,物理機的執行引擎是直接建立在處理器、快取、指令集和作業系統層面上的,而虛擬機的執行引擎則是由軟體自行實作的,可以不受物理條件制約地定制指令集與執行引擎的結構體系,能夠執行那些不被硬體直接支持的指令集格式,

  在不同的虛擬機實作中,執行引擎在執行位元組碼的時候,通常會有解釋執行(通過解釋器執行)和編譯執行(通過即時編譯器產生本地代碼執行)兩種選擇,也可能兩者兼備,還可能會有同時包含幾個不同級別的即時編譯器一起作業的執行引擎, 

  2. 運行時堆疊幀結構

  Java虛擬機以方法作為最基本的執行單元,“堆疊幀”(stack frame)則是用于支持虛擬機進行方法呼叫和方法執行背后的資料結構,每一個方法從呼叫開始到執行結束的程序,都對應著一個堆疊幀在虛擬機堆疊里面從入堆疊到出堆疊的程序,  

  一個執行緒中的方法呼叫鏈可能會很長,以Java程式的角度來看,同一時刻、同一條執行緒里面,在呼叫堆疊的所有方法都同時處于執行狀態,而對于執行引擎來講,在活動執行緒中,只有位于堆疊頂的方法才是在運行的, 只有位于堆疊頂的堆疊幀才是生效的, 其被稱為“當前堆疊幀”(Current Stack Frame) ,與這個堆疊幀所關聯的方法被稱為“當前方法”(Current Method) ,執行引擎所運行的所有位元組碼指令都只針對當前堆疊幀進行操作,在概念模型上,典型的堆疊幀結構如圖8-1所示,

  

  2.1 區域變數表

  區域變數表(Local Variables Table)是一組變數值的存盤空間,用于存放方法引數和方法內部定義的區域變數,

  由于區域變數表是建立在執行緒堆疊中的,屬于執行緒私有的資料,無論讀寫兩個連續的變數槽是否為原子操作,都不會引起資料競爭和執行緒安全問題,  

  當一個方法被呼叫時,Java虛擬機會使用區域變數表來完成引數值到引數變數串列的傳遞程序,即實參到形參的傳遞,  

  為了盡可能節省堆疊幀耗用的記憶體空間,區域變數表中的變數槽是可以重用的,方法體中定義的變數,其作用域并不一定會覆寫整個方法體,如果當前位元組碼PC計數器的值已經超出了某個變數的作用域,那這個變數對應的變數槽就可以交給其他變數來重用,

public static void main(String[] args)() {
    byte[] placeholder = new byte[64 * 1024 * 1024];
    System.gc();
}  
public static void main(String[] args)() {
    {
    byte[] placeholder = new byte[64 * 1024 * 1024];
    }
    System.gc();
}

  執行第一段代碼,沒有回收掉placeholder所占的記憶體是能說得過去,因為在執行System.gc()時,變數placeholder還處于作用域之內,  

  加入了花括號之后,placeholder的作用域被限制在花括號以內,從代碼邏輯上講,在執行System.gc()的時候,placeholder已經不可能再被訪問了,但執行這段程式,還是有64MB的記憶體沒有被回收掉,

public static void main(String[] args)() {
  {
  byte[] placeholder = new byte[64 * 1024 * 1024];
  }
  int a
= 0;   System.gc(); }

   placeholder能否被回收的根本原因就是:區域變數表中的變數槽是否還存有關于placeholder陣列物件的參考,第一次修改中,代碼雖然已經離開了placeholder的作用域,但在此之后,再沒有發生過任何對區域變數表的讀寫操作,placeholder原本所占用的變數槽還沒有被其他變數所復用,所以作為GC Roots一部分的區域變數表仍然保持著對它的關聯,

  2.2 運算元堆疊

  運算元堆疊(Operand Stack)是一個后入先出(Last In First Out,LIFO)堆疊,  

  當一個方法剛剛開始執行的時候,這個方法的運算元堆疊是空的,在方法的執行程序中,會有各種位元組碼指令往運算元堆疊中寫入和提取內容,也就是出堆疊和入堆疊操作,例如,整數加法的位元組碼指令iadd,在運行的時候要求運算元堆疊中最接近堆疊頂的兩個元素已經存入了兩個int型的數值,當執行這個指令時,會把這兩個int值出堆疊并相加,然后將相加的結果重新入堆疊,

  另外在概念模型中,兩個不同堆疊幀作為不同方法的虛擬機堆疊的元素,是完全相互獨立的,但是在大多虛擬機的實作里都會進行一些優化處理,令兩個堆疊幀出現一部分重疊,讓下面堆疊幀的部分運算元堆疊與上面堆疊幀的部磁區域變數表重疊在一起,這樣做不僅節約了一些空間,更重要的是在進行方法呼叫時就可以直接共用一部分資料,無須進行額外的引數復制傳遞了,重疊的程序如圖8-2所示,

  

  2.3 動態連接  

  Class檔案的常量池中存有大量的符號參考,位元組碼中的方法呼叫指令就以常量池里指向方法的符號參考作為引數,這些符號參考一部分會在類加載階段或者第一次使用的時候就被轉化為直接參考,這種轉化被稱為靜態決議,另外一部分將在每一次運行期間都轉化為直接參考,這部分就稱為動態連接,關于轉化的具體程序,將在第三節介紹,

  2.4 方法回傳地址  

  當一個方法開始執行后,只有兩種方式退出這個方法,

  第一種方式是執行引擎遇到任意一個方法回傳的位元組碼指令,這種退出方法的方式稱為“正常呼叫完成”(Normal Method Invocation Completion) ,

  另外一種退出方式是在方法執行的程序中遇到了例外,并且這個例外沒有在方法體內得到妥善處理,無論是Java虛擬機內部產生的例外,還是代碼中使用athrow位元組碼指令產生的例外,只要在本方法的例外表中沒有搜索到匹配的例外處理器,就會導致方法退出,這種退出方法的方式稱為“例外呼叫完成(Abrupt Method Invocation Completion) ”, 一個方法使用例外完成出口的方式退出,是不會給它的上層呼叫者提供任何回傳值的,

  方法退出的程序實際上等同于把當前堆疊幀出堆疊,需要恢復上層方法的區域變數表和運算元堆疊,把回傳值(如果有的話) 壓入呼叫者堆疊幀的運算元堆疊中,調整PC計數器的值以指向方法呼叫指令后面的一條指令等,

   3. 方法呼叫

  方法呼叫用來確定呼叫方法的版本,不涉及方法內部的具體運行程序,一切方法呼叫在Class檔案里面存盤的都只是符號參考,而不是方法在實際運行時記憶體布局中的入口地址(也就是之前說的直接參考) ,這個特性給Java帶來了更強大的動態擴展能力,但也使得Java方法呼叫程序變得相對復雜,

  3.1 決議

  在類加載的決議階段,會將其中一部分符號參考轉化為直接參考,但決議的前提條件是呼叫目標在程式代碼寫好、編譯器進行編譯那一刻就已經確定下來,

  在Java語言中符合“編譯期可知,運行期不可變”這個要求的方法,主要有靜態方法和私有方法兩大類,前者與型別直接關聯,后者在外部不可被訪問,這兩種方法各自的特點決定了它們都不可能通過繼承或別的方式重寫出其他版本,

  在Java虛擬機支持以下5條方法呼叫位元組碼指令:

  • invokestatic, 用于呼叫靜態方法,
  • invokespecial, 用于呼叫實體構造器<init>()方法、私有方法和父類中的方法,
  • invokevirtual, 用于呼叫所有的虛方法,
  • invokeinterface, 用于呼叫介面方法,會在運行時再確定一個實作該介面的物件,
  • invokedynamic, 先在運行時動態決議出呼叫點限定符所參考的方法,然后再執行該方法,前面4條呼叫指令,分派邏輯都固化在Java虛擬機內部,而invokedynamic指令的分派邏輯是由用戶設定的引導方法來決定的,

  只要能被invokestatic和invokespecial指令呼叫的方法,都可以在決議階段中確定唯一的呼叫版本,

  在類加載的時候就可以把符號參考決議為該方法的直接參考,這些方法統稱為“非虛方法”(Non-Virtual Method),與之相反,其他方法就被稱為“虛方法”(Virtual Method) ,

  3.2 分派

  3.2.1 靜態分派

  下面代碼中的“Human”稱為變數的“靜態型別”(Static Type),或者叫“外觀型別”(Apparent Type),后面的“Man”則被稱為變數的“實際型別”(Actual Type) 或者叫“運行時型別”(Runtime Type),靜態型別是在編譯期可知的;而實際型別變化的結果在運行期才可確定,編譯器在編譯程式的時候并不知道一個物件的實際型別是什么,

package org.fenixsoft.polymorphic;
/**
* 方法靜態分派演示
* @author zzm
*/
public class StaticDispatch {
    static abstract class Human {
    } 
    static class Man extends Human {
    } 
    static class Woman extends Human {
    } 
    public void sayHello(Human guy) {
        System.out.println("hello,guy!");
    } 
    public void sayHello(Man guy) {
        System.out.println("hello,gentleman!");
    } 
    public void sayHello(Woman guy) {
        System.out.println("hello,lady!");
    } 

public static void main(String[] args) {
    Human man = new Man();
    Human woman = new Woman();
    StaticDispatch sr = new StaticDispatch();
    sr.sayHello(man);
    sr.sayHello(woman);
    }
}        

   執行結果

hello,guy!
hello,guy!

  虛擬機(或者準確地說是編譯器)在多載時是通過引數的靜態型別而不是實際型別作為判定依據的,由于靜態型別在編譯期可知,所以在編譯階段,Javac編譯器就根據引數的靜態型別決定了會使用哪個多載版本,因此選擇了sayHello(Human)作為呼叫目標,把這個方法的符號參考寫到main()方法里的兩條invokevirtual指令的引數中,

  所有依賴靜態型別來決定方法執行版本的分派動作,都稱為靜態分派, 

  3.2.2 動態分派  

package org.fenixsoft.polymorphic;
/**
* 方法動態分派演示
* @author zzm
*/
public class DynamicDispatch {
    static abstract class Human {
        protected abstract void sayHello();
    } 
    static class Man extends Human {
        @Override
        protected void sayHello() {
            System.out.println("man say hello");
        }
    } 
    static class Woman extends Human {
        @Override
        protected void sayHello() {
            System.out.println("woman say hello");
        }
    } 
    public static void main(String[] args) {
        Human man = new Man();
        Human woman = new Woman();
        man.sayHello();
        woman.sayHello();
        man = new Woman();
        man.sayHello();
    }
}    

  運行結果

man say hello
woman say hello
woman say hello

  在運行期根據實際型別確定方法執行版本的分派程序稱為動態分派,通過invokevirtual指令實作,

  3.2.3 單分派與多分派

  方法的接收者與方法的引數統稱為方法的宗量,單分派是根據一個宗量對目標方法進行選擇,多分派則是根據多于一個宗量對目標方法進行選擇,  

/**
* 單分派、 多分派演示
* @author zzm
*/
public class Dispatch {
    static class QQ {}
    static class _360 {}
    public static class Father {
        public void hardChoice(QQ arg) {
            System.out.println("father choose qq");
        } 
        public void hardChoice(_360 arg) {
            System.out.println("father choose 360");
        }
    }
    public static class Son extends Father {
        public void hardChoice(QQ arg) {
            System.out.println("son choose qq");
        } 
        public void hardChoice(_360 arg) {
            System.out.println("son choose 360");
        }
   } 
    public static void main(String[] args) {
        Father father = new Father();
        Father son = new Son();
        father.hardChoice(new _360());
        son.hardChoice(new QQ());
    }
}    

  運行結果

father choose 360
son choose qq

  編譯階段編譯器選擇目標方法時(靜態分派),有兩點依據:一是靜態型別是Father還是Son,二是方法引數是QQ還是360,最侄訓產生兩條invokevirtual指令,兩條指令的引數分別為常量池中指向Father::hardChoice(360)及Father::hardChoice(QQ)方法的符號參考,

  動態分派時,在執行“son.hardChoice(new QQ())”這行代碼時,由于編譯期已經決定目標方法的簽名必須為hardChoice(QQ),虛擬機此時不會關心傳遞過來的引數“QQ”到底是“騰訊QQ”還是“奇瑞QQ”,因為這時候引數的靜態型別、實際型別都對方法的選擇不會構成任何影響,唯一可以影響虛擬機選擇的因素只有該方法的接受者的實際型別是Father還是Son,

  故而,Java語言是一門靜態多分派、動態單分派的語言,

  3.2.4 虛擬機動態分派實作

  動態分派是執行非常頻繁的動作,而且動態分派的方法版本選擇程序需要運行時在接收者型別的方法元資料中搜索合適的目標方法, 一種基礎而且常見的優化手段是為型別在方法區中建立一個虛方法表(Virtual Method Table,也稱為vtable,與此對應的,在invokeinterface執行時也會用到介面方法表——Interface Method Table,簡稱itable), 用虛方法表索引來代替元資料查找以提高性能,

    

  虛方法表中存放著各個方法的實際入口地址,如果某個方法在子類中沒有被重寫,那子類的虛方法表中的地址入口和父類相同方法的地址入口是一致的,都指向父類的實作入口,如果子類中重寫了這個方法,子類虛方法表中的地址也會被替換為指向子類實作版本的入口地址,為了程式實作方便,具有相同簽名的方法,在父類、子類的虛方法表中都應當具有一樣的索引序號,這樣當型別變換時,僅需要變更查找的虛方法表,就可以從不同的虛方法表中按索引轉換出所需的入口地址,虛方法表一般在類加載的連接階段進行初始化,準備了類的變數初始值后,虛擬機會把該類的虛方法表也一同初始化完畢,

  4. 動態型別語言支持  

  動態型別語言的關鍵特征是它的型別檢查的主體程序是在運行期而不是編譯期進行的,滿足這個特征的語言有很多,常用的包括:APL、Clojure、Erlang、Groovy、JavaScript、 Lisp、 Lua、 PHP、 Prolog、 Python、 Ruby、 Smalltalk、 Tcl, 等等, 那相對地, 在編譯期就進行型別檢查程序的語言, 譬如C++和Java等就是最常用的靜態型別語言,

  4.1 Java與動態型別

  JDK 7以前的位元組碼指令集中,4條方法呼叫指令(invokevirtual、 invokespecial、 invokestatic、invokeinterface) 的第一個引數都是被呼叫的方法的符號參考(CONSTANT_Methodref_info或者CONSTANT_InterfaceMethodref_info常量),方法的符號參考在編譯時產生,而動態型別語言只有在運行期才能確定方法的接收者,這樣,在Java虛擬機上實作的動態型別語言就不得不使用“曲線救國”的方式(如編譯時留個占位符型別,運行時動態生成位元組碼實作具體型別到占位符型別的適配)來實作,但這樣勢必會讓動態型別語言實作的復雜度增加,也會帶來額外的性能和記憶體開銷,

  比如有如下代碼:

var arrays = {"abc", new ObjectX(), 123, Dog, Cat, Car..}
for(item in arrays){
    item.sayHello();
}

  在動態型別語言下這樣的代碼是沒有問題,但由于在運行時arrays中的元素可以是任意型別,即使它們的型別中都有sayHello()方法,也肯定無法在編譯優化的時候就確定具體sayHello()的代碼在哪里,編譯器只能不停編譯它所遇見的每一個sayHello()方法,并快取起來供執行時選擇、呼叫和行內,如果arrays陣列中不同型別的物件很多,就勢必會對行內快取產生很大的壓力,快取的大小總是有限的,型別資訊的不確定性導致了快取內容不斷被失效和更新,先前優化過的方法也可能被不斷替換而無法重復使用,所以這種動態型別方法呼叫的底層問題終歸是應當在Java虛擬機層次上去解決才最合適,因此,在Java虛擬機層面上提供動態型別的直接支持就成為Java平臺發展必須解決的問題,這也是invokedynamic指令以及java.lang.invoke包出現的技術背景,

  4.2 java.lang.invoke 包

  JDK 7時新加入的java.lang.invoke包主要目的是在之前單純依靠符號參考來確定呼叫的目標方法這條路之外,提供一種新的動態確定目標方法的機制,稱為“方法句柄”(Method Handle) ,

  舉個例子,如果我們要實作一個帶謂詞(謂詞就是由外部傳入的排序時比較大小的動作)的排序函式,在C/C++中的常用做法是把謂詞定義為函式,用函式指標來把謂詞傳遞到排序方法,像這樣: 

void sort(int list[], const int size, int (*compare)(int, int))

  有了MethodHandle就可以寫出類似于C/C++那樣的函式宣告了:

void sort(List list, MethodHandle compare)

  如下為方法句柄實體代碼:  

import static java.lang.invoke.MethodHandles.lookup;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
/**
 * JSR 292 MethodHandle基礎用法演示
 * @author zzm
 */
public class MethodHandleTest {
    static class ClassA {
        public void println(String s) {
            System.out.println(s);
        }
    } 
    public static void main(String[] args) throws Throwable {
        Object obj = System.currentTimeMillis() % 2 == 0 ? System.out : new ClassA();
        // 無論obj最終是哪個實作類, 下面這句都能正確呼叫到println方法,
        getPrintlnMH(obj).invokeExact("icyfenix");
    } 
    private static MethodHandle getPrintlnMH(Object reveiver) throws Throwable {
        // MethodType: 代表“方法型別”, 包含了方法的回傳值(methodType()的第一個引數) 和
        具體引數(methodType()第二個及以后的引數) ,
        MethodType mt = MethodType.methodType(void.class, String.class);
        // lookup()方法來自于MethodHandles.lookup, 這句的作用是在指定類中查找符合給定的方法
        名稱、 方法型別, 并且符合呼叫權限的方法句柄,// 因為這里呼叫的是一個虛方法, 按照Java語言的規則, 方法第一個引數是隱式的, 代表該方法的接
        收者, 也即this指向的物件, 這個引數以前是放在引數串列中進行傳遞, 現在提供了bindTo()
        方法來完成這件事情,
        return lookup().findVirtual(reveiver.getClass(), "println", mt).bindTo(reveiver);
    }
}

  MethodHandle與Reflection的區別:

  • Reflection和MethodHandle機制本質上都是在模擬方法呼叫, 但是Reflection是在模擬Java代碼層次的方法呼叫, 而MethodHandle是在模擬位元組碼層次的方法呼叫,在MethodHandles.Lookup上的3個方法findStatic()、findVirtual()、findSpecial()正是為了對應于invokestatic、 invokevirtual(以及invokeinterface) 和invokespecial這幾條位元組碼指令的執行權限校驗行為,而這些底層細節在使用Reflection API時是不需要關心的,
  • Reflection中的java.lang.reflect.Method物件遠比MethodHandle機制中的java.lang.invoke.MethodHandle物件所包含的資訊來得多, 前者是方法在Java端的全面映像,包含了方法的簽名、描述符以及方法屬性表中各種屬性的Java端表示方式,還包含執行權限等的運行期資訊,而后者僅包含執行該方法的相關資訊,用開發人員通俗的話來講,Reflection是重量級,而MethodHandle是輕量級,
  • Reflection API的設計目標是只為Java語言服務的, 而MethodHandle則設計為可服務于所有Java虛擬機之上的語言

 

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/299287.html

標籤:其他

上一篇:測驗人員必備:《零成本實作Web性能測驗:基于Apache JMeter》

下一篇:金九銀十求職季,企業高頻面試題和答案都幫你準備好了,共17w字

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more