在C++中嵌入V8

C++应用嵌入V8引擎:实现JavaScript脚本扩展与双向通信 在现代软件开发中,脚本引擎嵌入技术为原生应用提供了强大的扩展能力。其核心原理在于将成熟的虚拟机(如V8)集成到宿主进程中,通过API桥接实现跨语言调用。这项技术的核心价值在于,它允许开发者在不重新编译主程序的情况下,动态加载和执行用户脚本,极大地提升了软件的灵活性和可定制性。典型的应用场景包括桌面软件的插件系统、游戏引擎的逻辑脚本、以及需要用户自定义规则的业务平台。本文聚焦于V8引擎,这是驱动Chrome和Node.js的高性能JavaScript虚拟机。我们将详细拆解如何在C++应用中初始化V8、执行Ja 阅读详情

本文翻译自 http://write.blog.youkuaiyun.com/postedit


Handle和垃圾收集

handle在v8中,用于记录js对象在堆中的位置。v8的垃圾收集器在收集那些不可到达的内存时,会对堆进行整理。它会移动对象的位置,以达到优化内存的目的。

当v8的垃圾收集器移动js对象的位置时,它会同时更新handle的值,让handle能够指向对象新的位置。


v 8中有两种handle

本地handle (LocalHandle) 。 这种handle存在于堆栈之上,并且在析构函数被调用时释放js对象。它的生命周期取决于handle scope, handle scope通常在函数调用的开始位置声明。当handle scope 被删除,垃圾收集器将回收被这些handle指向的对象。

Local Handle通过类 Handle<SomeType>来管理。



  • 注意:handle stack不同于c++的call stack。但是handle scope可以嵌入到c++的stack中。Handle scope只能是作为栈变量,不同通过new方法分配。

持久Handle (Persistent Handle)。持久Handle不再栈上分配,而且需要手动删除。同本地handle一样,持久handle也引用一个堆上分配的对象。当您希望在多个函数中调用一个对象,或者handle的生命周期超出c++的作用域的时候,就需要用持久handle了。

比如,google chrome就会使用持久handle保持一个DOM节点。创建一个支持hnandle,需要使用Persisten类的构造,删除则通过Persistent::Dispose。

通过Persistent::MakeWeak,持久handle可以被标记为 weak。

持久Handle使用 Persistent<SomeType>。


当你需要创建很多handle的时候,就需要用到handle scope。handle scope是一个handle容器。当handle scope被删除时,handle scope管理的所有handle都会被删除。


请看例子 使用C++调用V8 。下图介绍了例子中代码生成的handle对象。注意 Context::New()返回的是一个本地handle,我们为这个本地handle创建了一个持久handle来演示持久handle的用法。

当HandleScope::~HandleScope调用时,如果没有其他的引用,handle scope内的handle将在下次垃圾收集时被移除。

对象source_obj和script_obj将在他们不再被其他任何handle引用,也不会被javascript中的代码引用时被垃圾收集器回收。

但是context是一个持久handle,它将不会被回收,除非主动调用它的Dispose函数。


这里需要注意一个陷阱:你不能从一个声明了handle scope的函数中直接返回一个本地handle。这种情况下,在你返回local handle之前,handle scope就会将该handle删除。


正确的方式,是使用HandleScope::Close方法来返回。如下例:

// This function returns a new array with three elements, x, y, and z.
Handle<Array> NewPointArray(int x, int y, int z) {
  v8::Isolate* isolate = v8::Isolate::GetCurrent();

  // We will be creating temporary handles so we use a handle scope.
  HandleScope handle_scope(isolate); //声明了HandleScope了

  // Create a new empty array.
  Handle<Array> array = Array::New(3);

  // Return an empty result if there was an error creating the array.
  if (array.IsEmpty())
    return Handle<Array>();

  // Fill out the values
  array->Set(0, Integer::New(x));
  array->Set(1, Integer::New(y));
  array->Set(2, Integer::New(z));

  // Return the value through Close.
  return handle_scope.Close(array); //这样才能正确返回一个本地handle
}


Contexts

在v8中, context是一个分离的、独立的javascript执行环境。当你运行一段js代码时,你必须明确给出一个context。


为什么这是必须的?因为javascript提供了一组内建的函数和对象,这些都可以被javascript代码改变。如果两个完全不相关的javascript代码更改了全局的对象,就会造成不可预知的结果。


在CPU时间和内存角度看,创建一个执行环节似乎是一件很耗费时间和资源的事情,但是,v8通过广泛的缓存策略,仅让你第一次创建context时花销会比较大,后面再创建任意多的context的花销就很小了。


当第一次创建时,v8必须创建内建对象,并解析内建js代码。而后续context只需要创建他们自己的内建对象。


如果v8设置上了snapshot特性(build选项 snapshot=yes,这是默认值),第一次所花费的开销将大幅被优化。


当你创建了一个context后,你可以进入退出它任意多次。当你在context A的时候,你可以进入一个不同的context,B。这时,context B将取代A成为你的当前Context。 当你退出context B的时候,A就自动成为你的当前context:


注意:不同context内的内建函数和对象是相互分离的。


templates

一个template是javascript函数的蓝图。你可以使用一个template来将c++函数和结构体包装到javascript对象中,让javascirpt脚本来使用它。例如,google chrome使用template来包装c++ DOM节点为js对象,并提供全局访问函数。

你也可以创建一组template让所有的context来共享使用。你可以创建任意多的template。但是每个template在context中只有一个实例。


在javascript中,function和object有很大的重叠。在java和c++中,我们通过定义一个类来创建一个新的类型,而在javascirpt中,我们通过创建一个新的function,然后用这个function作为构造函数来创建一个实例。javascript对象的内存组织方式和功能都非常接近于创建它的函数。这影响到了v8 template的工作方法。

有两种template:

function template。这是创建一个独立函数的模板。创建一个javascript的template实例,需要通过template的GetFunction方法。你也可以给这个function template关联一个回调函数。当javascript函数实例调用时,这个回调会被访问。


object template。每个function template都会有一个关联的object template。这是为关联创建该对象的函数。你可以为object template关联两个类型的回调:

  • accessor callbacks : 当脚本访问特定对象的属性时调用;
  • interceptor callbacks 当脚本访问任意对象属性时调用;

下面的代码战士了如何使用template为全局对象增加内建函数的方法

// Create a template for the global object and set the
// built-in global functions.
Handle<ObjectTemplate> global = ObjectTemplate::New();
global->Set(String::New("log"), FunctionTemplate::New(LogCallback));

// Each processor gets its own context so different processors
// do not affect each other.
Persistent<Context> context = Context::New(NULL, global);


Accessors

一个accessor是一个c++的回调函数。当javascript脚本方位一个对象属性时,它被调用并返回一个值。

accessor通过object template来设置。使用SetAccessor方法。该方法需要提供一个属性名和关联的两个回调(读写)作为参数。


访问全局静态变量

假设有两个C++整型变量,x和y,被javascript当做全局变量来使用。要实现它,javascript需要调用C++的accessor函数。这些accessor函数通过Integer::New将C++整型转换为javascript整数;通过Int32Value将javascript整数转为c++整数。例子如下:

  Handle<Value> XGetter(Local<String> property, 
                        const AccessorInfo& info) {
    return Integer::New(x);
  }
    
  void XSetter(Local<String> property, Local<Value> value,
               const AccessorInfo& info) {
    x = value->Int32Value();
  }
       
  // YGetter/YSetter are so similar they are omitted for brevity
  
  Handle<ObjectTemplate> global_templ = ObjectTemplate::New();
  global_templ->SetAccessor(String::New("x"), XGetter, XSetter);
  global_templ->SetAccessor(String::New("y"), YGetter, YSetter);
  Persistent<Context> context = Context::New(NULL, global_templ);

注意:object template和context是同时创建的。object template可以被一次创建并被多个context使用。


访问动态变量

假设x和y是C++类Point的成员变量:

class Point {
   public:
    Point(int x, int y) : x_(x), y_(y) { }
    int x_, y_;
  }

如果让C++的point实例可以被javascript使用,我们需要为每个C++ point创建一个javascript对象,并且在javascript对象和c++对象之间建立关联。


第一步,创建针对Point对象的object template

Handle<ObjectTemplate> point_templ = ObjectTemplate::New();


javascript的point对象通过内部field来引用一个c++对象。 这个内部对象只能通过C++代码访问,不能通过javascript访问。 一个对象可以拥有任意多的内部field,它的数量通过如下函数设置:

 point_templ->SetInternalFieldCount(1);

这里,我们设置了一个长度为1的内部field,它的索引从0开始。


然后我们可以添加x和y的访问子:

  point_templ.SetAccessor(String::New("x"), GetPointX, SetPointX);
  point_templ.SetAccessor(String::New("y"), GetPointY, SetPointY);

下面,要将一个C++的point实例和javascript的代码关联。我们通过External对象来作为中介。因为javascript不知道如何处理一个c++对象。

  Point* p = ...;
  Local<Object> obj = point_templ->NewInstance();
  obj->SetInternalField(0, External::New(p));

External实际上是对一个void* 只针的封装。


下面,我们就可以实现对x和y的get和set访问了:

  Handle<Value> GetPointX(Local<String> property,
                          const AccessorInfo &info) {
    Local<Object> self = info.Holder();
    Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
    void* ptr = wrap->Value();
    int value = static_cast<Point*>(ptr)->x_;
    return Integer::New(value);
  }
  
  void SetPointX(Local<String> property, Local<Value> value,
                 const AccessorInfo& info) {
    Local<Object> self = info.Holder();
    Local<External> wrap = Local<External>::Cast(self->GetInternalField(0));
    void* ptr = wrap->Value();
    static_cast<Point*>(ptr)->x_ = value->Int32Value();
  }

Interceptors

有两种Interceptor,

  • 命名属性interceptor - 通过属性的字符串名来访问,如: document.theFormName.elementName
  • 索引属性interceptor - 通过索引访问的属性,如 document.forms.elements[0];


V8源代码中的示例process.cc展示了一个使用interceptors的例子。下面是SetNamedPropertyHandler中关于MapGet和MapSet的interceptor部分代码

Handle<ObjectTemplate> result = ObjectTemplate::New();
result->SetNamedPropertyHandler(MapGet, MapSet);


MapGet的interceptor如下

Handle<Value> JsHttpRequestProcessor::MapGet(Local<String> name,
                                             const AccessorInfo &info) {
  // Fetch the map wrapped by this object.
  map<string, string> *obj = UnwrapMap(info.Holder());

  // Convert the JavaScript string to a std::string.
  string key = ObjectToString(name);

  // Look up the value if it exists using the standard STL idiom.
  map<string, string>::iterator iter = obj->find(key);

  // If the key is not present return an empty handle as signal.
  if (iter == obj->end()) return Handle<Value>();

  // Otherwise fetch the value and wrap it in a JavaScript string.
  const string &value = (*iter).second;
  return String::New(value.c_str(), value.length());
}


安全模型

”同源“策略阻止不同源内的数据相互访问。


v8通过一个context定义一个”源“。默认情况下,跨context访问是不允许的。为了访问其他context,你需要一个安全token或者安全回调。

安全token可以是任意值,但是通常会使一个符号,一个全局唯一的字符串。你也可以通过SetSecurityToken来得到一个特殊的安全token。如果你不指定的话,v8会在你创建context时自动生成一个。


当一个对全局变量访问产生时,v8的安全系统首先检测全局对象的安全token和试图访问它的代码的安全token是否一致,如果token一致,那么访问将被授权。

如果token不一致,那么v8将通过一个回调来判断是否允许访问。

你可以通过SetAccessCheckCallbacks方法来设置这样一个回调。



异常

当有错误发生时,v8将抛出异常。如,当脚本或者函数试图访问一个不存在的属性时,或者对一个非函数进行调用时。


当操作不成功时,v8会返回一个空的handle。你的代码需要检查v8的返回值是否为空。这一点很重要。 通过函数IsEmpty()

你可以通过TryCatch来捕捉异常,如

  TryCatch trycatch;
  Handle<Value> v = script->Run();
  if (v.IsEmpty()) {  
    Handle<Value> exception = trycatch.Exception();
    String::AsciiValue exception_str(exception);
    printf("Exception: %s\n", *exception_str);
    // ...
  }

如果value返回为空,而且你没有一个TryCatch对象,那么你的代码会跳出。如果有TryCatch,异常就会被捕捉,你的代码会继续进行。


继承

javascript是一种无类别的面向对象语言,它使用原型继承来代替类继承。这让习惯传统面向对象语言的程序员困惑。


基于类的面对对象语言,如java, C++,是建筑在对类和对象严格区分的基础上的。javascript是一种基于原型的语言,因而没有这么严格的区分,它只有简单的对象。

javascript不能直接支持类继承,但是javacript的原型机制可以很简单的的实现自定义属性和方法的添加。在javascript中,你可以自定义对象的属性,如

// Create an object "bicycle" 
function bicycle(){ 
} 
// Create an instance of bicycle called roadbike
var roadbike = new bicycle()
// Define a custom property, wheels, on roadbike 
roadbike.wheels = 2

这个方法添加到了已经存在的对象实例上。

加入我创建另外一个bycycle的实例,如mountainbike,那么mountainbike.wheels将返回undefined,除非你用同样的方法添加它。


有时,很需要这种需求。希望为每个bycycle对象的实例头添加相同的书写。这是javascript原型对象有用的地方。使用原型对象,通过关键字prototype

// First, create the "bicycle" object
function bicycle(){ 
}
// Assign the wheels property to the object's prototype
bicycle.prototype.wheels = 2

这样所有的bicycle()实例都有了wheels属性。

同样的场景,在V8中通过template实现。每个FunctionTemplate都有一个PrototypeTemplate方法,可以设置function的原型。你可以设置属性、绑定c++函数等,这些都通过PrototypeTemplate作用到所有的实例上。如

 Handle<FunctionTemplate> biketemplate = FunctionTemplate::New();
 biketemplate->PrototypeTemplate().Set(
     String::New("wheels"),
     FunctionTemplate::New(MyWheelsMethodCallback)->GetFunction();
 )

这将使所有的 biketemplate  实例都有wheels方法。当实例的wheels被调用时,C++函数MyWheelsMethodCallback就会被调用。


V8的FunctionTemplate类还提供了一个公共方法Inhert(),你可以通过它来继承任意的FunctionTemplate,如

void Inherit(Handle<FunctionTemplate> parent);


七、嵌入v8引擎访问全局变量 参考《Getting started with embedding V8 · V8》 Accessing static global variables 首先,封装对全局变量的Set和Get方法: void GlobalValueGetter( Local<String> property, const PropertyCallbackInfo<Value>& info ) { info.GetReturnValue().Set( gValue... 阅读详情

相关推荐

VS2019编译V8引擎8.4生成DLL并嵌入C++项目的完整指南

JavaScript引擎为桌面应用提供了动态脚本扩展能力,其中V8引擎凭借高性能与完善的ES支持成为主流选择。然而,在Windows环境下编译V8并非易事,它高度依赖depot_tools工具链与GN构建系统,尤其在VS2019中,需要精确配置构建参数才能生成可用的动态链接库。通过设置is_component_build与v8_monolithic等选项,可以将V8核心模块合并为单个v8.dll及导入库,极大简化了后续C++项目的集成。对于需要嵌入JavaScript脚本的C++桌面应用,掌握这一编译流程能

weixin_42522669的博客 183

C++ V8 8.2的使用

​V8是一个开源的JS和WASM引擎,用C++编写,NODE就是基于V8搞的。项目中,需要对一部分动态的规则逻辑放在体外配置和执行,并且业务的规则是需要有逻辑控制的,这里用V8是再合适不过了。目前网上找到的资料和实例,在V8版本差异下有些许不同,这里就8.2给出正确示例。...

oShenLana的博客 980

VS2019编译V8引擎8.4:Release版DLL/LIB与C++嵌入实战

JavaScript引擎作为脚本执行的核心组件,其嵌入能力为桌面应用、游戏热更新和混合开发提供了强大的动态扩展基础。V8引擎凭借高性能与标准兼容性,成为众多开发者首选的嵌入对象,但Windows平台缺少官方预编译二进制,源码编译成为必经之路。理解V8的构建系统与产物形态是实现嵌入的关键:通过GN参数配置Release模式与组件构建,可获得动态链接库(DLL)及对应导入库(LIB),从而在自有工程中灵活集成。编译产物配合必要的ICU数据文件与启动快照,即可完成V8运行环境的搭建。在实际应用中,开发者需掌握Is

weixin_30129025的博客 330

Google V8 引擎 原理详解

Google V8 引擎使用 C++ 代码编写,实现了 ECMAScript 规范的第五版,可以运行在所有的主流 操作系统中,甚至可以运行在移动终端 ( 基于 ARM 的处理器,如 HTC G7 等 )。V8 最早被开发用以嵌入到 Google 的开源浏览器 Chrome 中,但是 V8 是一个可以独立的模块,完全可以嵌入您自己的应用,著名的 Node.js( 一个异步的服务器框架,可以在服务端使用 JavaScript 写出高效的网络服务器 ) 就是基于 V8 引擎的。 和其他 JavaScript

啊渊的专栏 2448

VS2010编译V8 JavaScript引擎库可嵌入C++

包含 VS2010编译出来的V8静态库 Release版 还有Demo代码

RK3588嵌入式AI部署实战:从环境搭建到模型推理全链路

嵌入式AI部署涉及交叉编译、NPU驱动、模型量化与运行时环境等多个技术环节,其核心挑战在于软硬件版本矩阵的严格匹配。在边缘计算场景中,RK3588凭借6TOPS NPU算力成为热门平台,但环境搭建与模型转换的复杂性常导致部署效率低下。通过容器化工具链管理、量化参数对齐及多线程推理优化,可显著提升部署稳定性与推理性能。典型应用包括智能安防、工业质检与视频结构化分析。本文围绕RK3588的AI部署与环境搭建,系统梳理从系统烧录到板端推理的完整实践路径。

weixin_42520573的博客 282

V8引擎原理

V8是用C++编写的Google开源高性能JavaScripti和WebAssembly引擎,它用于Chrome和Node,js等。它实现ECMAScript和WebAssembly,并在Windows7或更高版本,macOS10.12+和使用x64,lA-32,ARM或MIPS处理器的Linux系统上运行,V8可以独立运行,也可以嵌入到任何C++应用程序中。跨平台;

前端路漫漫,千万别偷懒 349

Flink 作业报错——TaskManager连接不上

Flink 作业报错——TaskManager连接不上

lm223的博客 1900

7分钟上手V8引擎:从C++嵌入到执行JavaScript的完整指南

你是否还在为如何在C++应用中集成高性能JavaScript引擎而烦恼?本文将以V8引擎官方示例为基础,带你快速掌握从环境搭建到执行复杂脚本的全过程。读完本文,你将能够: - 理解V8引擎核心组件的工作流程 - 编写能执行JavaScript代码的C++应用 - 掌握基础的API交互与内存管理 - 运行WebAssembly模块并与之通信 ## 什么是V8引擎? V8是Go...

gitblog_00122的博客 1168

Java判断地图坐标(经度,纬度)是否在多边形区域或圆形区域内

​欢迎光临我的博客查看最新文章:在地图上,可以使用经纬度确定一个位置,如上海体育场(121.449391,31.188228),如果知道了2个地点的经纬度,我们就能在地图上找到其位置及2点的距离,百度地图或高德地图提供了相应的服务;如果将多个坐标点连成多边形区域,如何判断某个坐标点是否在多边形区域内,如下工具类。

river106的博客 3942

Kali使用Metasploit内、外网渗透windows系统

Metasploit是一个免费的、可下载的框架,通过它可以很容易地获取、开发并对计算机软件漏洞实施攻击。它本身附带数百个已知软件漏洞的专业级漏洞攻击工具。当H.D. Moore在2003年发布Metasploit时,计算机安全状况也被永久性地改变了。 一、(内网渗透)内网英文缩写WAN;内网又称局域网 局域网的覆盖范围一般是方圆几千米之内,其具备的安装便捷、成本节约、扩展方便等特点使其在各类办公室内运用广泛。局域网可以实现文件管理、应用软件共享、打印机共享等功能,在使用过程当中,通过维护局域网网...

QQ670663的博客 2万+

V8 嵌入指南:用 C++ 在应用中集成 V8 JavaScript 引擎

V8 是 Google 开源的 C++ 高性能 JavaScript 与 WebAssembly 引擎,既可作为独立虚拟机运行,也可作为普通 C++ 库嵌入到任意宿主应用中。本指南以 V8 官方文档 [docs/embed.md](https://link.gitcode.com/i/a247acb20c8bd38a82ee27906d276a89) 为主体,结合本仓库提供的 [samples/h

gitblog_00698的博客 679

Manus创始人深度复盘:AI Agent产品的技术架构与战略转型

成本对比:同样任务处理,中国区单位成本是亚太区的2.3倍。付费转化率:中国区1.2% vs 全球平均4.7%微信/支付宝等超级App的适配代码占比达17%Zstandard:压缩比38%,耗时12ms。每季度需要投入3名高级工程师专职维护兼容性。国际版API平均延迟:180-220ms。中国版特殊部署延迟:480-720ms。信息保持准确率:93%(7天跨度测试)自研算法:压缩比39%,耗时5ms。存储效率:相比纯文本节省68%空间。:本地化部署导致的延迟与费用差异。LZ4:压缩比42%,耗时8ms。

m0_75253143的博客 7146

保姆级教程: c++游戏服务器嵌入v8 js引擎

导语|本文将介绍在c++游戏服务器上嵌入v8 js引擎的详细教程,关键步骤都会附带完整的可运行代码。并在文末为您附上github仓库链接。逐渐有些原生语言项目因为希望有不停机更新的能力...

QcloudCommunity的博客 2001

OpenStack [ compute_id ] 设计上的小缺陷

而 nova 代码中硬编码(或默认配置)将 compute_id 放在 site-packages 目录,属于 设计上的小缺陷—— 把 “库安装目录” 和 “运行时数据目录” 混在一起了,才导致需要临时调整这个目录的权限。# 配置项说明:node_identity_file 是 nova 用于指定节点标识文件路径的官方配置项,优先级高于代码中的默认路径。自定义 compute_id 路径,指向 /var/lib/nova/ 目录下的 compute_id 文件;

求知若渴,虚心若愚。 491

[SoC]SoC验证中bootcode与firmware相关验证经验总结

本文总结了SoC验证中bootcode和firmware的验证经验。重点介绍了两种数据加载方法:1)使用Verilog系统函数$readmemh/$readmemb直接写入ROM/ARAM,需注意文件路径、格式和斜杠方向;2)通过Memory Hierarchy在initial块中操作,需要添加适当延时并注意路径拼接。文章还提供了在testcase phase中先读取数据到HASH再写入SRAM的示例,并强调加载后需使能edc_bypass以避免ECC错误。验证过程中需特别注意文件位置、格式要求及路径处理等

元直的博客 2497

在C++中嵌入JavaScript——Google V8 JavaScript Engine使用

Google V8 JavaScript Engine是google为 Chrome's浏览器开发的脚本引擎,现在可以使用V8 JavaScript Engine在C++程序中建立自己的脚本环境。 1.准备工作 1). 安装一个SVN客户端http://tortoisesvn.net/downloads,google v8 在官方网站仅以此方式发布; 2).下载一个p...

yanlijun250 515

Keras神经网络可视化模块keras.utils.visualize_util的安装配置方法

本文介绍了如何安装和配置keras.utils.visualize_util模块,并提供了一个简单的示例演示如何使用该模块来可视化神经网络的结构。在上述代码中,我们首先定义了一个简单的神经网络模型,该模型具有一个输入层、一个隐藏层和一个输出层,其中隐藏层具有512个神经元,输出层具有10个神经元。运行上述代码后,我们将在当前工作目录下找到一个名为model.png的文件,它显示了神经网络的结构图。这种方式有效地展示了整个过程,让我们能够更好地理解神经网络的结构,方便对其进行改进和调试。

. 892

V8 官方文档导读:从源码构建、嵌入 C++ 到引擎内部架构的完整指南

V8 是 Google 开源的、用 C++ 编写的高性能 JavaScript 与 WebAssembly 引擎,被广泛应用于 Chrome 浏览器与 Node.js。本文是仓库中 [docs/index.md](https://link.gitcode.com/i/65e13368ab6a6ba747c9da1adbc4a637) 文档的深度导读,面向两类读者:想在自有 C++ 应用中嵌入 V8

gitblog_00820的博客 342

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

在C++中嵌入JavaScript——Google V8 JavaScript Engine使用体验

feedback 2195410 #1楼 2010-02-21 01:14 jeffrey zhao 呃,javascript是不能缩写为jsp的……jsp是java server page的缩写。 回复 引用 查看 #2楼[楼主] 2010-02-21 01:22 johnsonfeng 啊,一时疏忽,本来要写成js,结果误作jsp,多谢提醒:) 回复 引用 查看

javazhuanzai的专栏 627

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

提升C++嵌入V8引擎性能的方法

好的,在提升 C 嵌入 V8 引擎性能的方面,你可以尝试以下几种方法: 优化代码:尽量使用性能更优的代码,避免使用低效的代码。 启用编译优化选项:在编译代码时,启用优化选项,这会使编译器生成更优秀的代码。 使用高效的数据结构:选择合适的数据结构,能够提升代码的性能。 使用多线程:在多核 CPU 上使用多线程,能够提升代码的性能。 使用内存优化:减少内存的使用,能够提升代码的性能。 使用...

weixin_35749786的博客 311

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

上一篇: 使用C++调用V8
下一篇: ubutun12.04解决不能启动xserver的问题
漂流的代码
博客等级 码龄23年 188粉丝 99原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值