diff --git a/.gitignore b/.gitignore
index 0062d901c69f434b6ba9ff948b04d518b8953988..09ad6c6bd43e351302b2b58bc98cd35b8d4fcdb3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,5 +3,6 @@
 /Cargo.lock
 .depend
 /.vscode
-copy.bat
+copy_debug.bat
+copy_release.bat
 build_no_warning.bat
diff --git a/build.bat b/build_debug.bat
similarity index 94%
rename from build.bat
rename to build_debug.bat
index f9702559f98255f6022afc811486a6dbae3bd838..a49154ad1699bef00c1b9b82257d2107725eefae 100644
--- a/build.bat
+++ b/build_debug.bat
@@ -8,4 +8,5 @@ if not defined PI_JS_PROXY_TS_PATH (
 
 cargo clean -p pi_serv
 cargo b
+
 pause;
diff --git a/build_release.bat b/build_release.bat
new file mode 100644
index 0000000000000000000000000000000000000000..bf8460bed060e7b670eb731e79fa591f28e73358
--- /dev/null
+++ b/build_release.bat
@@ -0,0 +1,12 @@
+if not defined PI_JS_PROXY_EXT_CRATES (
+    set PI_JS_PROXY_EXT_CRATES=..\pi_core_lib;..\pi_serv_lib
+)
+
+if not defined PI_JS_PROXY_TS_PATH (
+    set PI_JS_PROXY_TS_PATH=..\pi_pt
+)
+
+cargo clean -p pi_serv
+cargo b --release
+
+pause;
diff --git a/copy1.bat b/copy1.bat
deleted file mode 100644
index 42210a37aefdf4dc6b68db0a66f99e8abb8b5fb3..0000000000000000000000000000000000000000
--- a/copy1.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-copy target\debug\pi_serv.exe E:\work\source\Game\school_1\libs\pi_pt\bin\release
-pause;
\ No newline at end of file
diff --git a/src/hotfix.rs b/src/hotfix.rs
index 533d4db8ddc006b11a4df39d62e0a8008ff51bbe..fdb38c9027d90ef2361be875032c8382ba40be8b 100644
--- a/src/hotfix.rs
+++ b/src/hotfix.rs
@@ -1,11 +1,14 @@
+use std::collections::HashMap;
 use std::env;
 use std::ffi::OsString;
 use std::mem::forget;
 use std::path::PathBuf;
+use std::sync::atomic::{AtomicUsize, Ordering};
 use std::sync::Arc;
 
 use dunce::canonicalize;
 use json::stringify;
+use parking_lot::Mutex;
 
 use atom::Atom;
 use file::fs_monitor::{FSChangeEvent, FSListener, FSMonitor, FSMonitorOptions};
@@ -16,6 +19,12 @@ use crate::js_net::HTTP_STATIC_CACHES;
 use crate::MAIN_ASYNC_RUNTIME;
 use crate::VID_CONTEXTS;
 
+lazy_static! {
+    pub static ref HOTFIX_FILES: Arc<Mutex<HashMap<String, usize>>> =
+        Arc::new(Mutex::new(HashMap::new()));
+    static ref HOTFIX_VERSION: Arc<AtomicUsize> = Arc::new(AtomicUsize::new(0));
+}
+
 const INIT_FILE: &str = "pi_pt/init.js";
 
 fn module_changed(change_path: PathBuf, prefix: PathBuf) {
@@ -34,6 +43,11 @@ fn module_changed(change_path: PathBuf, prefix: PathBuf) {
             break;
         }
 
+        // 递增版本号
+        let ver = HOTFIX_VERSION.fetch_add(1, Ordering::Relaxed);
+        // 如果是已经存在的文件,则使用原来的版本号; 新文件则使用新的版本号
+        HOTFIX_FILES.lock().entry(path.clone()).or_insert(ver);
+
         match GRAY_MGR.read().vm_instance(0, vid.clone()) {
             Some(vm) => {
                 // 虚拟机的每个context重新require该模块
diff --git a/src/init.rs b/src/init.rs
index bd2081ed22022a4654a224d1a065f757d04779a8..547086d734f725534429a06af5352b07b4df6f53 100644
--- a/src/init.rs
+++ b/src/init.rs
@@ -38,7 +38,12 @@ pub async fn read_init_source(init_exec_path: String) -> String {
     }
 }
 
-pub async fn init_js(is_debug_mode: bool, init_vm: vm::Vm, handle: ContextHandle, matches: ArgMatches<'static>) {
+pub async fn init_js(
+    is_debug_mode: bool,
+    init_vm: vm::Vm,
+    handle: ContextHandle,
+    matches: ArgMatches<'static>,
+) {
     let init_exec_path = if is_debug_mode {
         "../dst_server/pi_pt/debug_init.js".to_string()
     } else {
diff --git a/src/main.rs b/src/main.rs
index 9707f3642928d3484ca6c490e861b8b268a3b47c..fda8d13e7ce9e7fddf4f506e1e59b0612eab17cb 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -27,6 +27,7 @@ use std::{env, fs::read_to_string};
 
 use clap::{App, Arg, ArgMatches, SubCommand};
 use env_logger;
+use json::stringify;
 use num_cpus::get_physical;
 use parking_lot::{Condvar, Mutex, RwLock, WaitTimeoutResult};
 
@@ -57,7 +58,7 @@ use pi_core_builtin::set_external_async_runtime;
 use pi_core_lib::set_file_async_runtime;
 use pi_serv_ext::register_ext_functions;
 use pi_serv_lib::{js_db::global_db_mgr, js_gray::GRAY_MGR};
-use pi_serv_lib::{set_pi_serv_lib_file_runtime, set_pi_serv_lib_main_async_runtime};
+use pi_serv_lib::{set_pi_serv_lib_file_runtime, set_pi_serv_lib_main_async_runtime, set_store_runtime};
 #[cfg(feature = "profiling_heap")]
 use profiling_pi_core::{
     console::{set_console_shell_ctrlc_handler, ConsoleShell, ConsoleShellBuilder},
@@ -71,7 +72,7 @@ mod init;
 mod js_net;
 
 use crate::js_net::create_listener_pid;
-use hotfix::{hotfix_listen_backend, hotfix_listen_frontend};
+use hotfix::{hotfix_listen_backend, hotfix_listen_frontend, HOTFIX_FILES};
 use init::{init_js, read_init_source};
 use js_net::{create_http_pid, reg_pi_serv_handle, start_network_services};
 
@@ -305,6 +306,7 @@ async fn async_main(
     // 加载native funtion
     register_ext_functions();
 
+    set_store_runtime(FILES_ASYNC_RUNTIME.clone()).await;
     // 注册文件异步运行时
     set_file_async_runtime(FILES_ASYNC_RUNTIME.clone());
     set_pi_serv_lib_file_runtime(FILES_ASYNC_RUNTIME.clone());
@@ -425,6 +427,7 @@ fn init_http_listener_pid() {
 fn reigster_vms_events(workers: &[vm::Vm], is_debug_mode: bool) {
     // 设置虚拟机的事件回调
     for worker in workers {
+        let vm = worker.clone();
         let event_handler = VmEventHandler::new(
             AsyncRuntime::Local(MAIN_ASYNC_RUNTIME.clone()),
             move |event, vid| match event {
@@ -433,6 +436,55 @@ fn reigster_vms_events(workers: &[vm::Vm], is_debug_mode: bool) {
                         "Vm event handler: VmEventValue::CreatedContext, vid = {:?}, cid = {:?}",
                         vid, context.0
                     );
+
+                    // 非调试模式下才需要重新require热更过的文件
+                    if !is_debug_mode {
+                        // 获取已经热更新过的文件
+                        let mut hotfixed_files = HOTFIX_FILES
+                            .lock()
+                            .iter()
+                            .map(|(key, val)| (key.clone(), val.clone()))
+                            .collect::<Vec<(String, usize)>>();
+                        // 按版本号从小到大排序
+                        hotfixed_files.sort_by(|a, b| a.1.cmp(&b.1));
+
+                        for (path, _) in hotfixed_files {
+                            let vm = vm.clone();
+                            let _ = MAIN_ASYNC_RUNTIME.spawn(MAIN_ASYNC_RUNTIME.alloc(), async move {
+                                if let Ok(Some(func)) = vm
+                                    .get_property(context.clone(), "self.Module.require")
+                                    .await
+                                {
+                                    let p = vm
+                                        .to_js_value(context.clone(), stringify(path.clone()))
+                                        .await
+                                        .unwrap()
+                                        .unwrap();
+                                    let dir = vm
+                                        .to_js_value(context.clone(), stringify(""))
+                                        .await
+                                        .unwrap()
+                                        .unwrap();
+                                    let force = vm
+                                        .to_js_value(context.clone(), stringify(true))
+                                        .await
+                                        .unwrap()
+                                        .unwrap();
+                                    if let Err(_e) = vm
+                                        .call(context.clone(), &func, vec![p.clone(), dir, force])
+                                        .await
+                                    {
+                                        warn!("hotfix call require error");
+                                    } else {
+                                        debug!("new context update hotfix file, vid = {:?}, cid = {:?}, path = {:?}", vid, context.0, path);
+                                    }
+                                } else {
+                                    warn!("get Module.require error");
+                                }
+                            });
+                        }
+                    }
+
                     VID_CONTEXTS
                         .lock()
                         .entry(vid)